본문 바로가기

코딩 테스트(Coding test)/BOJ

[BOJ 2579번/C++] 계단 오르기

미숙한 블로그 주인이 코딩테스트 문제를 풀어가는 과정을 담은 글입니다. 이 풀이가 효율적인 풀이가 아닐 수 있으며, 부정확한 정보가 많이 있을 수 있습니다. 보완해야할 점이 있다면 댓글로 남겨주세요!

 

https://www.acmicpc.net/problem/2579

 

2579번: 계단 오르기

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점

www.acmicpc.net

계단 오르기

문제

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

<그림 1>

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

<그림 2>

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

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

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

 

제한사항

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

 

풀이

먼저 규칙을 찾아야한다. 그것을 위해 처음부터 하나하나 경우를 따져나가본다.

 

계단 = [ 10, 20, 15, 25, 10, 20 ]

 

1. 첫 번째 계단까지의 점수

이 경우는 시작 - 첫 번째 계단이라는 경우밖에 없다.

DP[1] = 10

 

2. 두 번째 계단까지의 점수

이 경우는 마찬가지로 시작 - 첫 번째 계단 - 두 번째 계단이라는 경우밖에 없다.

DP[2] = 10 + 20 = 30

 

3. 세 번째 계단까지의 점수

이 경우는 시작 - 첫 번쨰 계단 - 두 번째 계단 - 세 번째 계단의 방식으로는 구할 수 없다. 문제에 불가능한 조건이라고 되어있기 때문이다.

그래서 아래와 같이 두 가지의 경우로 나뉜다.

 

3-1) 시작 - 첫 번째 계단 - 세 번째 계단

DP[3] = 10 + 15 = 25

 

3-2) 시작 - 두 번째 계단 - 세 번째 계단

DP[3] = 20 + 15 = 35

 

3-2)의 경우가 값이 더 크므로, DP[3] = 35이다.

 

4. 네 번째 계단까지의 점수

이 경우는 더 다양한 방법이 존재한다.

 

4-1) 시작 - 첫 번째 계단 - 두 번째 계단 - 네 번째 계단

DP[4] = 10 + 20 + 25 = 55

 

4-2) 시작 - 첫 번째 계단 - 세 번째 계단 - 네 번째 계단

DP[4] = 10 + 15 + 25 = 50

 

4-3) 시작 - 두 번째 계단 - 네 번째 계단

DP[4] = 20 + 25 = 45

 

가장 큰 경우는 4-1)인 경우이므로, DP[4] = 55이다.

그런데, 4-3)의 경우는 척 봐도 4-1)의 경우보다 작음을 알 수 있다.

그러므로, 이제부터 4-3)과 같은 경우는 배제해준다.

 

이때까지의 경우를 보고 점화식을 세워보자.

DP[1]과 DP[2]의 경우는 항상 한 가지 경우밖에 없다.

 

DP[1] = Score[1]

DP[2] = DP[1] + Score[2]

 

 

DP[3]의 경우를 보자.

3-1)의 경우는 풀어쓰면 DP[1] + Score[3] 과 같다.

 

3-2)의 경우는 Score[2] + Score[3] 과 같다.

 

즉, DP[3] = max(DP[1] + Score[3], Score[2] + Score[3])

 

 

DP[4]의 경우를 보자.

4-1)의 경우는 DP[2] + Score[4]와 같다.

 

4-2)의 경우는 DP[1] + Score[3] + Score[4]와 같다.

 

즉, DP[4] = max(DP[2] + Score[4], DP[1] + Score[3] + Score[4])

 

위 과정들을 통해 DP[i] = max(DP[i - 2] + Score[i], DP[i - 3] + Score[i - 1] + Score[i]) 라는 점화식을 세워본다.

 

 

이제 이 점화식이 맞는지를 보자.

 

5. 다섯 번째 계단까지의 점수

위의 네 번째 계단까지의 경우보다 더 많은 경우의 수가 있다.

 

5-1) 시작 - 첫 번째 계단 - 두 번째 계단 - 네 번째 계단 - 다섯 번째 계단

두 번째 계단까지의 점수는 DP[2]이다. 그렇다면, 5-1)은 DP[5] = DP[2] + Score[4] + Score[5]와 같다.

 

5-2) 시작 - 첫 번째 계단 - 세 번째 계단 - 다섯 번째 계단

5-3) 시작 - 두 번째 계단 - 세 번째 계단 - 다섯 번째 계단

 

이 둘을 묶어서 보면, 결국에는 DP[5] = DP[3] + Score[5]와 같다.

DP[3]의 값이 max(DP[1] + Score[3], Score[2] + Score[3])이기 때문이다.

 

5-4) 시작 - 두 번째 계단 - 네 번째 계단 - 다섯 번째 계단 : 이 경우는 5-1)에 비해 무조건 값이 작다.

 

위 검증을 통해 점화식이 맞음을 알았다.

 

#include <iostream>

using namespace std;

int dp[301];
int score[301];

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

    for (int i = 1; i <= N; i++) {
        int p;

        cin >> p;
        
        score[i] = p;
    }

    dp[1] = score[1];
    dp[2] = score[2] + dp[1];
    for (int i = 3; i <= N; i++) {
        dp[i] = max(dp[i - 3] + score[i - 1] + score[i], dp[i - 2] + score[i]);
    }

    cout << dp[N] << endl;

    return 0;
}

 

 

'코딩 테스트(Coding test) > BOJ' 카테고리의 다른 글

[BOJ 10844번/C++] 쉬운 계단 수  (0) 2022.09.15
[BOJ 1463번/C++] 1로 만들기  (0) 2022.09.14
[BOJ 1149번/C++] RGB거리  (0) 2022.09.12
[BOJ 1912번/C++] 연속합  (0) 2022.09.11
[BOJ 9461번/C++] 파도반 수열  (0) 2022.09.10