알고리즘/문제 풀이
2096번: 내려가기
Themion
2021. 12. 14. 13:20
https://www.acmicpc.net/problem/2096
2096번: 내려가기
첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 숫자가 세 개씩 주어진다. 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 중의 하나가 된다.
www.acmicpc.net
일반적인 DP와는 다르게 최댓값과 최솟값을 모두 구해야 하므로, 각 위치에 도달했을 때의 최댓값과 최솟값을 계산해 저장한 뒤 마지막 층에서의 최댓값과 최솟값을 출력하면 된다.
#include <iostream>
using namespace std;
#define INF 900000
// prev[i]: 처음부터 바로 직전의 i번째 칸까지 이동할 때
// 얻을 수 있는 점수의 최대/최솟값
int max_[2][3], min_[2][3];
void set_max(int &a, int b) { a = a > b ? a : b; }
void set_min(int &a, int b) { a = a < b ? a : b; }
void dp(bool idx) {
// 현재 줄의 세 칸
int now[3];
// 현재 층에서의 최댓값 / 최솟값을 초기화
fill_n(max_[idx], 3, 0);
fill_n(min_[idx], 3, INF);
// 현재 층의 점수를 저장
cin >> now[0] >> now[1] >> now[2];
// 이전 칸에서 i번쨰 칸에 도착할 수 있는 세 칸에 대해
for (int i = 0; i < 3; i++) for (int j = i - 1; j <= i + 1; j++) {
// 칸의 인덱스가 범위를 벗어났다면 continue
if (j < 0 || j > 2) continue;
// i번째 칸에 도착할 수 있는 값의 최대/최소값을 저장
max_[idx][i] = max(max_[idx][i], max_[!idx][j] + now[j]);
min_[idx][i] = min(min_[idx][i], min_[!idx][j] + now[j]);
}
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N;
// 층 수를 입력받은 뒤 각 층마다 최댓값과 최솟값을 계산
cin >> N;
for (int i = 0; i < N; i++) dp(i % 2);
// 모든 칸에서의 최대/최소값을 게산하여 출력
for (int i = 1; i < 3; i++) {
max_[!(N % 2)][0] = max(max_[!(N % 2)][0], max_[!(N % 2)][i]);
min_[!(N % 2)][0] = min(min_[!(N % 2)][0], min_[!(N % 2)][i]);
}
cout << max_[!(N % 2)][0] << ' ' << min_[!(N % 2)][0] << '\n';
return 0;
}