✏️ 문제 분석
https://www.acmicpc.net/prablem/2096
N개의 줄에 숫자가 세 개씩 주어지고, 세 개 중 하나를 고르면서 아래로 내려가는 게임을 한다.
다음 줄의 숫자로 내려갈 때는, 바로 아래 또는 바로 아래와 인접한 수로만 내려갈 수 있다.
얻을 수 있는 최대 점수, 최소 점수를 구하여라.
✏️ 구현 아이디어
3
1 2 3
4 5 6
4 9 0
숫자표를 이차원 배열 dp라고 했을 때,
두 번째 줄 이상(n>0)에서 다음과 같은 규칙이 적용된다.
- dp[n][0]은 dp[n-1][0], dp[n-1][1]
- dp[n][1]은 dp[n-1][0], dp[n-1][1], dp[n-1][2]
- dp[n][2]은 dp[n-1][1], dp[n-1][2]
로부터 내려올 수 있다.
| dp[0][0] | dp[0][1] | dp[0][2] |
| dp[1][0] |
예를 들어 dp[1][0]은 dp[0][0], dp[0][1]로부터 내려올 수 있다.
만약 최대 점수를 구하는 중이라면 둘 중 더 큰 숫자를,
최소 점수를 구하는 중이라면 더 작은 숫자를 dp[1][0]에 더해서 dp[1][0]값을 갱신한다.
최대 점수 : dp[1][0] + max(dp[0][0], dp[0][1])
최소 점수 : dp[1][0] + min(dp[0][0], dp[0][1])
| dp[0][0] | dp[0][1] | dp[0][2] |
| dp[1][1] |
마찬가지로 dp[1][1]은 dp[0][0], dp[0][1], dp[0][2]로부터 내려올 수 있다.
최대 점수 : dp[1][1] + max(dp[0][0], dp[0][1], dp[0][2])
최소 점수 : dp[1][1] + min(dp[0][0], dp[0][1], dp[0][2])
| dp[0][0] | dp[0][1] | dp[0][2] |
| dp[1][2] |
최대 점수 : dp[1][2] + max(dp[0][1], dp[0][2])
최소 점수 : dp[1][2] + min(dp[0][1], dp[0][2])
이런 방식으로 n-1행까지 수행한다. (단, 최댓값, 최솟값을 별도의 배열로 구함)
✏️ 알고리즘
이전에 구했던 답을 다음 문제를 푸는 데 사용하는 방법이므로, dp를 사용하는 것이 적절하다.
✏️ 시간 복잡도
dp는 모든 노드를 한 번만 방문하므로 시간 복잡도가 O(N)이다.
노드는 최대 100,000개이므로 시간 제한(1초) 안에 모두 연산할 수 있다.
✏️ 코드 설계
- 값 입력받기
- 최대값, 최소값 구할 이차원 배열 dpMax, dpMin 각각 선언
- 두 번째 행부터 좌표당 findMax(), findMin() 수행
- 0열 : 이전 행의 0, 1열 중 최대/최솟값 + 현재값
- 1열 : 이전 행의 0, 1, 2열 중 최대/최솟값 + 현재값
- 2열 : 이전 행의 1, 2열 중 최대/최솟값 + 현재값
- 을 누적한다.
- dpMax, dpMin의 n-1행을 정렬한 후, 최대/최솟값을 각각 출력
✏️ 정답 코드
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int n;
static int[][] dpMax, dpMin;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//값 입력받기
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
dpMax = new int[n][3];
dpMin = new int[n][3];
for(int i = 0; i< n; i++){
st = new StringTokenizer(br.readLine());
for(int j=0; j<3; j++){
int val = Integer.parseInt(st.nextToken());
dpMax[i][j] = dpMin[i][j] = val;
}
}
for(int i = 1; i< n; i++){
dpMax[i][0] += Math.max(dpMax[i-1][0], dpMax[i-1][1]);
dpMax[i][1] += Math.max(Math.max(dpMax[i-1][0], dpMax[i-1][1]), dpMax[i-1][2]);
dpMax[i][2] += Math.max(dpMax[i-1][1], dpMax[i-1][2]);
dpMin[i][0] += Math.min(dpMin[i-1][0], dpMin[i-1][1]);
dpMin[i][1] += Math.min(Math.min(dpMin[i-1][0], dpMin[i-1][1]), dpMin[i-1][2]);
dpMin[i][2] += Math.min(dpMin[i-1][1], dpMin[i-1][2]);
}
Arrays.sort(dpMax[n-1]);
Arrays.sort(dpMin[n-1]);
System.out.println(dpMax[n-1][2] + " " + dpMin[n-1][0]);
}
}'코테' 카테고리의 다른 글
| [백준/Java] 2503번 : 숫자 야구 (1) | 2025.01.15 |
|---|---|
| [백준/Java] 13567번 : 로봇 (0) | 2025.01.14 |
| [백준/Java] 1149번 : RGB 거리 (1) | 2025.01.12 |
| [백준/Java] 14430번 : 자원 캐기 (0) | 2025.01.11 |
| [백준/Java] 9095번 : 1, 2, 3 더하기 (0) | 2025.01.10 |