문제 정보
- 백준 실버 1
- DP
- 문제 링크
풀이
현재 단계에서 최적인 값을 알 수 없고, 현재 선택한 값이 이후 선택 가능한 값의 범위에 영향(현재에서 대각선 왼쪽이나 오른쪽만 가능)을 미치기 때문에, DP를 사용하는 문제다.
dp 배열을 다음과 같이 정의한다.
dp[i][j]: i 단계의 j번째 원소에 도착했을 때의 최대값.
그렇기에 점화식은 dp[i][j] = triangle[i][j] + max(dp[i - 1][j - 1], dp[i - 1][j])가 된다. 다만 대각선 왼쪽이나 오른쪽이 없는 왼쪽 끝이나 오른쪽 끝은 따로 처리해줘야 한다.
피보나치 수를 구할 때나 20260203 RGB 거리처럼, 현재 단계의 값을 구할 때 이전 행의 값만 필요하다. 그렇기에 이전 행 전체를 저장할 필요 없이 1차원 배열을 재사용하는 방식으로 공간을 최적화할 수 있다.
이때, j를 역순(오른쪽 → 왼쪽)으로 순회해야 한다는 점을 주의해야 한다.
순방향으로 순회할 경우, dp[j-1]이 이미 현재 행의 값으로 덮어써진 상태가 되어 이전 행의 값을 참조할 수 없게 된다. 역순으로 순회하면 dp[j-1]이 아직 이전 행의 값을 유지하고 있으므로 올바르게 참조할 수 있다.
코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = i; j >= 1; j--) {
int element = Integer.parseInt(st.nextToken());
if (j == 1) {
dp[j] = element + dp[j];
continue;
}
dp[j] = element + Math.max(dp[j - 1], dp[j]);
}
}
int answer = 0;
for (int i = 1; i <= n; i++)
answer = Math.max(answer, dp[i]);
System.out.println(answer);
}
}