백준 2579 계단 오르기 [c++]

계단오르기 실버3

문제

계단 오르는 데는 다음과 같은 규칙이 있다.

계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다. 마지막 도착 계단은 반드시 밟아야 한다. 따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

문제 풀이

dp문제 계단의 점수를 입력받는 arr와 해당 계단의 최댓값을 저장하는 dp배열 2개를 이용.(0이 아닌 1부터 사용)

  • step 1 :
    • dp[1] = arr[1]
    • 1번 계단 까지의 최대는 당연히 1번 점수
  • step 2 :
    • dp[2] = arr[1] + arr[2]
  • step 3 :
    • 1번계단 + 두 계단 올라간 3번계단” or “두 계단 올라간 2번 계단 + 3번 계단” 중 큰 값.
  • step 4:
    • “2번까지 최대 + 4번” or “1번까지 최대 + 3 + 4번” 중 큰 값.
  • 점화식 : “n-2번 계단 까지 최대값 + n번” or “n-3번까지 최대 + n-1 + n번” 중 큰 값.
  • dp[n] = max(dp[n-2] + arr[n], dp[n-3] + arr[n - 1] + arr[n])

코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int dp[302];
int arr[302];

void up_stair(int n)
{
    dp[1] = arr[1];
    dp[2] = arr[1] + arr[2];
    dp[3] = max(arr[1] + arr[3], arr[2] + arr[3]);
    
    for(int i = 4; i <= n; i++)
    {
        dp[i] = max(dp[i-2] + arr[i], dp[i-3] + arr[i-1] + arr[i]);
    }
}

int main(){
    int n;
    cin >> n;

    for(int i = 1; i <= n; i++)
    {
        cin >> arr[i];
        dp[i] = 0;
    }
    
    up_stair(n);

    cout << dp[n] << endl;

    return 0;
}

총평

  • 점화식만 잘 쓰면 쉽게 풀리는 문제
  • 처음에 dp로 안풀고 greedy로 접근했음
  • 예제는 맞게 나왔지만 반례 존재했음
  • n이 크지않고 문제가 동일한 하위 문제를 반복적으로 계산하므로 DP가 적합!!