[알고리즘] 동적 계획법(Dynamic Programming, DP)
2024. 12. 28. 15:35ㆍCS
1. 동적 계획법(Dynamic Programming)이란?
동적 계획법은 큰 문제를 작은 문제로 나누어 푸는 분할 정복(Divide and Conquer) 기법의 일종으로, 부분 문제의 결과를 재사용하여 중복 계산을 줄이는 알고리즘 설계 기법이다.
2. 동적 계획법의 특징
1. 최적 부분 구조(Optimal Substructure)
- 큰 문제의 최적해가 작은 부분 문제의 최적해로 구성된다.
2. 중복되는 부분 문제(Overlapping Subproblems)
- 동일한 작은 문제를 여러 번 반복하여 풀게 되는 성질이 있다.
- 이 중복 계산을 줄이기 위해 결과를 저장한다.
3. 동적 계획법의 장단점
장점
- 중복 계산을 제거하여 효율성을 극대화
- 재귀적 접근보다 명확하고 빠른 해결 가능
단점
- 상태 저장을 위한 추가 메모리 공간 필요
- 문제에 최적 부분 구조가 없으면 적용 불가
4. 동적 계획법의 접근 방법
1. 상향식 접근(Bottom-Up)
- 작은 문제부터 해결해 결과를 저장하고, 이를 기반으로 큰 문제를 해결
- 일반적으로 테이블(Tabluation) 방식으로 구현
2. 하향식 접근(Top-Down)
- 큰 문제를 해결하기 위해 작은 문제를 재귀적으로 호출하며 결과를 저장
- 일반적으로 메모이제이션(Memoization) 방식으로 구현
5. 동적 계획법의 시간 복잡도
- 동적 계획법의 시간 복잡도는 문제의 부분 문제 수와 각 부분 문제를 푸는 데 걸리는 시간의 곱으로 계산된다.
- 예: 피보나치 수열의 DP 구현 -> O(n)
6. 동적 계획법의 활용 예시
1. 최적 경로 찾기
- 예: 다익스트라(Dijkstra), 벨만-포드(Bellman-Ford)
2. 배낭 문제(Knapsack Problem)
- 제한된 무게 내에서 최대 가치를 찾는 문제
3. 최장 공통 부분 수열(LCS, Longest Common Subsequence)
- 두 문자열의 간의 최장 공통 부분을 찾는 문제
4. 동전 거스름돈 문제
- 최소 동전 개수로 거스름돈을 만드는 방법 찾기
7. 동적 계획법의 구현 예제
예제 1: 피보나치 수열
1. 재귀 방식 (비효율적)
public class FibonacciRecursive {
public static int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) {
System.out.println(fibonacci(10)); // 출력: 55
}
}
2. 메모이제이션 방식 (Top-Down)
import java.util.*;
public class FibonacciMemoization {
private static Map<Integer, Integer> memo = new HashMap<>();
public static int fibonacci(int n) {
if (n <= 1) return n;
if (memo.containsKey(n)) return memo.get(n);
int result = fibonacci(n - 1) + fibonacci(n - 2);
memo.put(n, result);
return result;
}
public static void main(String[] args) {
System.out.println(fibonacci(10)); // 출력: 55
}
}
3. 테이블 방식 (Bottom-Up)
public class FibonacciTabulation {
public static int fibonacci(int n) {
if (n <= 1) return n;
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
public static void main(String[] args) {
System.out.println(fibonacci(10)); // 출력: 55
}
}
동적 계획법은 복잡한 문제를 효율적으로 해결할 수 있는 강력한 도구이다.
특히 코딩 테스트에서 빈번히 등장하므로, 재귀와 반복을 활용한 구현 방식 모두 숙달해 두는 것이 중요하다.
'CS' 카테고리의 다른 글
[자료구조] List Map Set의 차이와 활용(Java) (0) | 2025.01.03 |
---|---|
[알고리즘] 백트래킹(Backtracking) (1) | 2024.12.28 |
[알고리즘] BFS(너비 우선 탐색)와 DFS(깊이 우선 탐색) (0) | 2024.12.21 |
[알고리즘] 탐욕 알고리즘(Greedy Algorithm) (0) | 2024.12.21 |
[자료구조] ArrayList와 LinkedList의 차이 (Java) (0) | 2024.12.21 |