[Programmers] 완전범죄
DP
DP (Dynamic Programming)은 문제를 작은 부분 문제로 나누고, 그 부분 문제의 결과를 저장해서 동일한 계산을 반복하지 않도록 최적화할 때 사용된다.
DP 사용 가능한 조건
-
중복 부분 문제
-> 동일한 작은 문제가 여러 번 반복해서 나타남
-> ex) 피보내치 수열 계산 -
최적 부분 구조
-> 큰 문제의 최적해가 작은 문제의 최적해로부터 구성됨
-> ex) 최단 경로, 최소 비용, 최대 점수 등
문제 유형 | 설명 | 예시 |
---|---|---|
최적화 문제 | 최대값/최소값을 구하는 문제 | 최대 이익, 최소 비용, 최소 거리 등 |
조합 문제 | 특정 조건을 만족하는 경우의 수 | 계단 오르기, 동전 교환, 문자열 분할 등 |
문자열 처리 | 문자열의 부분 구조나 패턴 분석 | 최장 공통 부분 수열 (LCS), 편집 거리 등 |
경로 탐색 | 특정 조건을 만족하는 경로 수나 최적 경로 | 미로 탈출, 그래프의 최단 경로 등 |
완전범죄 (프로그래머스) 또한 최적해를 찾는 문제이므로 DP를 사용해서 풀면 빠르고 쉽게 풀 수 있다.
접근
- 목표 : A도둑의 흔적을 최소화하면서 B도둑의 흔적이 m 미만이어야 함
- dp[i][j] : i번째 물건까지 고려했을 때, B의 흔적(j) 유지, a의 최소합
-> a의 최소합을 b를 증가시켜가면서 풂으로써 최적해를 구하고자 함.
초기화
- dp[0][0] = 0 // 시작 시 흔적 X
- 나머지는 A도둑이 최대로 남길 수 있는 흔적인 n으로 초기화
점화식
- A 도둑 : dp[i][b] = min(dp[i][b], dp[i-1][b] + A흔적)
- B 도둑 : dp[i][b+B흔적] = min(dp[i][b+B흔적], dp[i-1][b])
모든 물건 탐색 후 dp[info.length][b] 중 b<m
인 경우 최소값 반환. 만약 모든 경우에서 b >= m이면 -1을 반환
코드
class Solution {
int[][] dp;
public int solution(int[][] info, int n, int m) {
dp = new int[info.length + 1][m];
// 초기화
for (int i = 1; i <= info.length; i++) {
Arrays.fill(dp[i], n);
}
dp[0][0] = 0;
// DP 수행
for (int i = 1; i <= info.length; i++) {
int a = info[i - 1][0];
int b = info[i - 1][1];
for (int j = 0; j < m; j++) {
// A도둑이 물건을 훔치는 경우
dp[i][j] = Math.min(dp[i][j], dp[i - 1][j] + a);
// B도둑이 물건을 훔치는 경우
if (j + b < m)
dp[i][j + b] = Math.min(dp[i][j + b], dp[i - 1][j]);
}
}
// 정답 반환
int answer = n;
for (int j = 0; j < m; j++) {
answer = Math.min(answer, dp[info.length][j]);
}
return answer >= n ? -1 : answer;
}
}
DP vs Dijkstra
항목 | 다이나믹 프로그래밍 (DP) | 다익스트라 알고리즘 |
---|---|---|
문제 유형 | 최적화 문제 (최솟값, 최댓값, 경우의 수 등) | 최단 경로 문제 (그래프에서) |
입력 구조 | 주로 배열, 표, 수열 | 그래프 (노드, 간선, 가중치) |
중복 부분 문제 | O (중복 계산 피함) | X (각 노드는 1번만 최단 경로 갱신) |
사용 조건 | 최적 부분 구조 + 중복 부분 문제 | 가중치 ≥ 0인 그래프 |
구현 방식 | 보통 2차원 배열, 상태 정의 + 점화식 | 우선순위 큐 + 방문 체크 |
예시 문제 | 배낭 문제, 계단 오르기, LCS 등 | 최단 경로, 길찾기, 네트워크 등 |
- DP는 모든 가능한 경우를 다 계산하되, 같은 건 반복하지 않도록 저장하는 것이고, 다익스트라는 현재 가장 짧은 거리로 도착한 노드부터 확장해 최단 거리만 갱신한다는 것으로 이해하면 이해가 쉽다.
참고 자료
- https://velog.io/@parksegun/%EC%99%84%EC%A0%84%EB%B2%94%EC%A3%84-Java