미숙한 블로그 주인이 코딩테스트 문제를 풀어가는 과정을 담은 글입니다. 이 풀이가 효율적인 풀이가 아닐 수 있으며, 부정확한 정보가 많이 있을 수 있습니다. 보완해야할 점이 있다면 댓글로 남겨주세요!
https://www.acmicpc.net/problem/2579
계단 오르기
문제
문제
계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.
<그림 1>
예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.
<그림 2>
계단 오르는 데는 다음과 같은 규칙이 있다.
- 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
- 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
- 마지막 도착 계단은 반드시 밟아야 한다.
따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.
각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.
제한사항
입력
입력의 첫째 줄에 계단의 개수가 주어진다.
둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 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 |