계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.
계단 오르는 데는 다음과 같은 규칙이 있다.
각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.
입력
입력의 첫째 줄에 계단의 개수가 주어진다.
둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.
출력
첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.
BOJ2579
알고리즘 분류는 DP 문제였지만, 반복문으로 풀 수 있을것같아 이쪽으로 먼저 접근했다. 마지막 계단을 꼭 밟아야 한다는 조건이 있으므로, 마지막 계단부터 시작해서 자신의 전 칸과 전전칸을 비교하여 더 큰 계단으로 내려가는 식으로 코드를 작성했는데, 이런 식으로 생각하면 무조건적인 최대값이 나오지 않는게 확인됐다. (세 칸 규칙이 있으므로, 때로는 작은 칸으로 이동하여 2칸 이동하는게 더 클 때도 존재한다.)
다시 돌아와 DP 문제로 해결하기 위해 점화식을 생각했다. 계단의 N번째 칸에 도착하는 방법은, N-2에서 두 칸 이동하거나, N-1에서 한 칸 이동하는 방법이지만, N-1에 도착할 때 N-2에서 한 칸 이동했다면 N-1에서 또 다시 한 칸 이동할 순 없다. 따라서 N-1에서 한 칸 이동할 경우엔 N-3에서 두 칸 이동하여 N-1로 도착하는 경우밖에 없다.
DP[N]을 N계단 까지 최대값이라고 생각한다면, DP[N-2] + N계단의 값과 DP[N-3] + N-1계단의 값 + N계단의 값 중 더 큰값이라고 볼 수 있다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int [] stair = new int[301];
static int [] dp = new int[301];
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(bf.readLine());
for(int i = 1; i <= n; i++)
stair[i] = Integer.parseInt(bf.readLine());
dp[0] = 0;
dp[1] = stair[1];
dp[2] = stair[1] + stair[2];
dp[3] = Math.max(stair[1] + stair[3], stair[2] + stair[3]);
for(int i = 4; i <= n; i++) {
dp[i] = Math.max(stair[i] + dp[i-2], stair[i] + stair[i-1] + dp[i-3]);
}
System.out.println(dp[n]);
}
}