문제링크 : https://www.acmicpc.net/problem/21317
21317번: 징검다리 건너기
산삼을 얻기 위해 필요한 영재의 최소 에너지를 출력한다.
www.acmicpc.net
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;
int N, K, dp[21][2];
pii arr[21];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for(int i=1; i<N; i++)
{
int a, b;
cin >> a >> b;
arr[i] = {a, b};
}
cin >> K;
for(int i=0; i<=N; i++)
{
dp[i][0] = MAX;
dp[i][1] = MAX;
}
dp[1][0] = 0;
dp[2][0] = arr[1].first; //두번째 돌
for(int i=3; i<=N; i++)
{
dp[i][0] = min(arr[i-1].first + dp[i-1][0], arr[i-2].second+dp[i-2][0]); //작은 점프
dp[i][1] = min({arr[i-1].first + dp[i-1][1], arr[i-2].second+dp[i-2][1], K+dp[i-3][0]}); //큰 점프 + 매우 큰 점프
}
cout << min(dp[N][0], dp[N][1]);
return 0;
}
우선 매우 큰 점프 사용유무를 고려하여 dp 식을 세운다.
그리고 dp 식에서 최소값을 찾아야 하기에 우선 MAX 값으로 초기화를 진행해준다.
맨 처음에 해당하는 dp[1][0]은 시작점이기에 에너지 소모가 없으므로 0으로 초기화해주고,
두 번째에 해당하는 dp[2][0]은 케이스가 맨 처음에서 작은 점프하는 경우 밖에 없으므로 해당 값(작은 점프 값)으로 초기화해준다.
이제 반복문을 돌리며 i=3 ~ N까지 dp 식을 갱신하게 된다.
먼저 케이스를 살펴보면 다음과 같은 케이스가 존재한다.
작은 점프 -> 작은 점프
작은 점프 -> 큰 점프
큰 점프 -> 작은 점프
큰 점프 -> 큰 점프
0 1 차이는 매우 큰 점프 사용 유무 (1이 사용)
직전 작은 점프 : dp[i-1][0] or dp[i-1][1]
현재 작은 점프 : arr[i-1].first
직전 큰 점프 : dp[i-2][0] or dp[i-2][1]
현재 큰 점프 : arr[i-2].second
위 케이스에 대한 값들을 조합하여 dp 식을 갱신하게 된다.
이제 추가적으로 고려해야 하는 것은 큰 점프이다.
큰 점프의 경우 3칸을 점프하기에 반복문을 i=3부터 시작한 이유이기도 하다.
매우 큰 점프를 사용한 dp식을 갱신 할때 기존의 작은 점프, 큰 점프, 엄청 큰 점프 이렇게 3가지 값을 고려하게 된다.
현재 매우 큰 점프를 사용한 dp식이기 떄문에 작은 점프 및 큰 점프는 0이 아닌 1의 값을 가지게 된다.
하지만 매우 큰 점프의 경우 여태 사용하지 않고 이번에 사용하는 것이기 때문에 1이 아닌 0의 값을 가지게 된다.
(dp[i-3][0])
만약 dp[i-3][1] 이라면 이미 엄청 큰 점프를 사용했는데 또 사용하는 것을 의미하게 된다.
이후 엄청 큰 점프를 사용한 것과 아닌 것 중 (dp[N][0], dp[N][1]) 더 작은 값을 골라 출력해주면 된다.
'백준 > 골드' 카테고리의 다른 글
[백준 16974번] 레벨 햄버거 (C++) (0) | 2024.02.24 |
---|---|
[백준 9177번] 단어 섞기 (C++) (0) | 2024.02.17 |
[백준 1519번] 부분 문자열 뽑기 게임 (C++) (0) | 2024.02.14 |
[백준 1354번] 무한 수열 2 (C++) (0) | 2024.02.12 |
[백준 23815번] 똥게임 (C++) (0) | 2024.02.09 |