알고리즘/DP
[BOJ] 백준 2096 - 내려가기 풀이
송승현(SSH)
2023. 3. 12. 22:44
1. 문제
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
2. 풀이 Point
- 각 행 별로 선택할 수 있는 경우의 수는 세 가지다. (첫 번째, 두 번째, 세 번째)
- 그리고 각 경우의 수를 선택했을 때 다음을 고를 경우의 수는 세 가지이다.
- 따라서 0번 열, 1번 열, 2번 열을 각각 메모이제이션 해주어야 하므로 dp를 2차원 배열로 만든다.
- 각 경우의 수를 골랐을 때의 최대 값은 다음과 같은 형식으로 식을 세울 수 있다.
- 최소 값도 이와 마찬가지로 N - 1까지 계산한 후 3가지 경우에 대해 최대 값, 최소 값을 구하면 정답!!
3. 소스 코드
// 첫 번째 : 최대 최소를 각각 나눠서 처리하기
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int N = Integer.parseInt(br.readLine());
int[][] map = new int[N][3];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < 3; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
// 최대 구하기
int[][] dp = new int[N][3];
dp[0][0] = map[0][0];
dp[0][1] = map[0][1];
dp[0][2] = map[0][2];
for (int i = 1; i < N; i++) {
dp[i][0] += map[i][0] + Math.max(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] += map[i][1] + Math.max(Math.max(dp[i - 1][0], dp[i - 1][1]), dp[i - 1][2]);
dp[i][2] += map[i][2] + Math.max(dp[i - 1][1], dp[i - 1][2]);
}
String maxResult = Integer.toString(Math.max(dp[N - 1][0] , Math.max(dp[N - 1][1], dp[N - 1][2]))); // 최대 값
// 최소 구하기
dp = new int[N][3];
dp[0][0] = map[0][0];
dp[0][1] = map[0][1];
dp[0][2] = map[0][2];
for (int i = 1; i < N; i++) {
dp[i][0] += map[i][0] + Math.min(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] += map[i][1] + Math.min(Math.min(dp[i - 1][0], dp[i - 1][1]), dp[i - 1][2]);
dp[i][2] += map[i][2] + Math.min(dp[i - 1][1], dp[i - 1][2]);
}
String minResult = Integer.toString(Math.min(dp[N - 1][0] , Math.min(dp[N - 1][1], dp[N - 1][2]))); // 최소 값
bw.write(maxResult + " " + minResult);
bw.flush();
bw.close();
br.close();
}
}
// 두 번째 : 한 번에 처리하기
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
static class MaxMinObject {
int max;
int min;
public MaxMinObject(int max, int min) {
this.max = max;
this.min = min;
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int N = Integer.parseInt(br.readLine());
int[][] map = new int[N][3];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < 3; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
MaxMinObject[][] dp = new MaxMinObject[N][3];
dp[0][0] = new MaxMinObject(map[0][0], map[0][0]);
dp[0][1] = new MaxMinObject(map[0][1], map[0][1]);
dp[0][2] = new MaxMinObject(map[0][2], map[0][2]);
for (int i = 1; i < N; i++) {
dp[i][0] = new MaxMinObject(map[i][0] + Math.max(dp[i - 1][0].max, dp[i - 1][1].max),
map[i][0] + Math.min(dp[i - 1][0].min, dp[i - 1][1].min));
dp[i][1] = new MaxMinObject(map[i][1] + Math.max(Math.max(dp[i - 1][0].max, dp[i - 1][1].max), dp[i - 1][2].max),
map[i][1] + Math.min(Math.min(dp[i - 1][0].min, dp[i - 1][1].min), dp[i - 1][2].min));
dp[i][2] = new MaxMinObject(map[i][2] + Math.max(dp[i - 1][1].max, dp[i - 1][2].max),
map[i][2] + Math.min(dp[i - 1][1].min, dp[i - 1][2].min));
}
bw.write(Math.max(dp[N - 1][0].max, Math.max(dp[N - 1][1].max, dp[N - 1][2].max)) + " " + Math.min(dp[N - 1][0].min, Math.min(dp[N - 1][1].min, dp[N - 1][2].min)));
bw.flush();
bw.close();
br.close();
}
}
4. 배운점
- 시간이 넉넉하다면 머리속으로 떠오르는 생각 그대로 작성하는 것도 좋은 방법이다.
5. 점수
90/100