프로그래밍/백준 알고리즘

백준 알고리즘 2579번 - 계단 오르기

good programmer 2019. 5. 7. 16:08

대표적인 dp문제라고 할 수 있다.

 나는 dp[계단 위치][바로 전에 올라간 칸수] 배열을 선언했다.

또 마지막 칸은 무조건 밟기 때문에 계단을 뒤집어서 맨 마지막 칸을 맨 처음 칸으로 바꿔서 계산하자.(이렇게 풀어야 예외처리 필요없이 일관성있는 코드가 될 것같다)

 

이렇게 분할하면 바로 전에 1칸 올라간 경우, 2칸 올라간 경우를 따로 계산해 주어야 한다.

이때 생각 해주어야 하는 게 있는데,

한 칸 올라간 경우에는 바로 전에 올라간 계단 수가 무조건 두 칸이여야 하고

두 칸 올라간 경우에는 바로 전에 올라간 계단의 수가 상관없다.

 

점화식으로 나타내면 ,

dp[i][2]=max(dp[i-2][2],dp[i-2][1])+arr[i]

dp[i][1]=dp[i-1][2])+arr[i]

 

주의 해야할 것은 마지막 계단을 출력하는게 아닌,

dp[마지막][1], dp[마지막][2] , dp[마지막-1][1], dp[마지막-1][2] 중 가장 큰 걸 출력해야한다

(처음에 두칸을 뛸 수도 있고 한 칸을 뛸 수도 있기 때문)

 

소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Example program
#include <iostream>
#include <algorithm>
 
using namespace std;
 
int main()
 
{
    int arr[301];
    int dp[301][3]={0,};
    int n; 
    int ans=0;
    cin>>n;
    
    //배열을 입력한다 
    /*
    마지막 계단을 무조건 밟으므로 배열을 뒤집자
    */
    for(int i=1;i<=n;i++cin>>arr[n-i+1];
    
    //초기값 지정
    dp[2][1]=arr[1]+arr[2];
    dp[3][2]=arr[1]+arr[3];
    
    //memoization
    /*
    점화식 dp[i][2]=max(dp[i-2][2],dp[i-2][1])+arr[i]
           dp[i][1]=dp[i-1][2]+arr[i]
    
    */
    for(int i=4;i<=n;i++){
        dp[i][1]=dp[i-1][2]+arr[i];
        dp[i][2]=max(dp[i-2][2],dp[i-2][1])+arr[i];
    }
    
    //마지막 위치가 맨 처음 계단 일 수도 있고, 2번째 계단 일 수도 있다. 
    //처음에 2칸을 뛸 수도 있기 때문
    for(int i=n-1;i<=n;i++){
        for(int j=1;j<=2;j++)
            if(ans<dp[i][j]) ans=dp[i][j];
    }
    cout<<ans;
}
 
cs