※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 25499번 문제인 Tipover Transform이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/25499
25499번: Tipover Transform
첫째 줄에 $N$이 주어진다. $(3 \le N \le 300\,000)$ 둘째 줄에 $N$개의 정수 $A_1, A_2, \ldots, A_N$이 공백으로 구분되어 주어진다. $A_i$는 $2$ 이상 $N$ 이하의 정수 또는 $0$이다. $A_i = 0$인 경우 처음에 $i$번
www.acmicpc.net
주어지는 모든 블록은 결국 모두 적어도 한 번씩은 밟고 지나가야 함을 관찰하자.
위 관찰에 따라, 각 블록이 쓰러진 방향에 대하여 해당 블록의 왼쪽 끝까지 도달하기 위해 필요한 최소 큐브블록 개수를 이전 블록의 쓰러진 방향에 따른 각 상태의 왼쪽 끝까지 도달하기 위해 필요한 큐브블록의 수를 이용해 나타낼 수 있음을 알 수 있다. 즉, 이전 블록의 (쓰러진 방향에 따른) 왼쪽 끝까지 도달하기 위해 필요한 최소 큐브블록 개수와 현재 블록의 (쓰러진 방향에 따른) 왼쪽 끝까지 도달하기 위해 필요한 최소 큐브블록 개수 사이에는 점화관계가 존재함을 알 수 있다.
이와 같은 점화관계를 이용해 dp로 문제를 해결해주자.
아래는 제출한 소스코드이다.
#include <iostream>
#include <vector>
using namespace std;
int N, M;
pair<int, int> seg[300001][3]; // 0: 서있음, 1: 왼쪽쓰러짐, 2: 오른쪽쓰러짐
int dp[300001][3];
int ans = 1000000007;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
seg[0][0] = seg[0][1] = seg[0][2] = { 0,0 };
cin >> N;
for (int i = 1; i <= N; i++) {
int h; cin >> h;
if (h) {
M++;
seg[M][0] = { i,i };
seg[M][1] = { i - h,i - 1 };
seg[M][2] = { i + 1,i + h };
}
}
for (int i = 1; i <= M; i++) {
dp[i][0] = dp[i][1] = dp[i][2] = 1000000007;
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
if (seg[i - 1][j].second < seg[i][k].first) dp[i][k] = min(dp[i][k], dp[i - 1][j] + (seg[i][k].first - seg[i - 1][j].second - 1));
}
}
}
ans = min(dp[M][0] + (N - seg[M][0].second), dp[M][1] + (N - seg[M][1].second));
if (seg[M][2].second <= N) ans = min(ans, dp[M][2] + (N - seg[M][2].second));
cout << ans;
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 25496 // C++] 장신구 명장 임스 (0) | 2023.09.25 |
---|---|
[BOJ 25497 // C++] 기술 연계마스터 임스 (0) | 2023.09.24 |
[BOJ 25500 // C++] 무자비한 최단 경로 (0) | 2023.09.22 |
[BOJ 24620 // C++] Sleeping in Class (0) | 2023.09.21 |
[BOJ 24621 // C++] Photoshoot 2 (0) | 2023.09.20 |