동적 계획법이란?
동적 계획법(Dynamic Programming, DP) 은 큰 문제를 겹치는 작은 문제들로
쪼개고, 한 번 푼 작은 문제의 답을 저장해 두어 다시 풀지 않는 기법입니다.
재귀에서 같은 계산을 수없이 반복하던 것을, "한 번 구한 답은 적어 두고 재사용"
하는 것으로 바꾸면 지수 시간이 다항 시간이 됩니다.
1. DP가 통하는 두 조건
- 겹치는 부분 문제(overlapping subproblems): 같은 작은 문제가 여러 번 등장한다.
- 최적 부분 구조(optimal substructure): 작은 문제의 최적해로 큰 문제의 최적해를
만들 수 있다.
이 두 조건이 보이면 DP를 의심하세요. 피보나치, 계단 오르기, 배낭 문제가
대표적입니다.
2. 두 가지 구현 방식
| 방식 | 방향 | 구현 |
|---|---|---|
| 메모이제이션(top-down) | 큰 → 작은 | 재귀 + 캐시 |
| 타뷸레이션(bottom-up) | 작은 → 큰 | 반복문 + 배열 |
둘은 같은 점화식을 다른 순서로 채울 뿐 본질은 같습니다. 재귀가 자연스러우면
메모이제이션, 반복이 깔끔하면 타뷸레이션을 씁니다.
3. DP 설계의 3단계
DP 문제는 거의 항상 이 순서로 풉니다.
- 상태 정의:
dp[i]가 무엇을 의미하는지 명확히 정한다.
(예:dp[i]= \(i\)번째 계단까지 오는 경우의 수) - 점화식 세우기:
dp[i]를 더 작은dp들로 표현한다.
(예:dp[i] = dp[i-1] + dp[i-2]) - 초기값과 순서: 가장 작은 상태(기저)를 정하고, 의존하는 순서대로 채운다.
상태를 무엇으로 잡느냐가 DP의 8할입니다. 상태가 잘 정의되면 점화식은 따라옵니다.
4. 예: 계단 오르기
한 번에 1칸 또는 2칸 오를 수 있을 때 \(N\)칸 오르는 방법의 수.
$$ dp[i] = dp[i-1] + dp[i-2] $$
\(i\)번째 칸에 오는 마지막 발걸음이 1칸이었으면 \(dp[i-1]\)에서, 2칸이었으면
\(dp[i-2]\)에서 왔기 때문입니다. 초기값 \(dp[0]=1, dp[1]=1\).
이 "마지막 선택으로 경우를 나눈다"는 사고가 점화식의 핵심입니다.
5. 복잡도
DP의 복잡도는 보통 (상태의 개수) × (한 상태를 계산하는 비용) 입니다.
- 1차원 상태 \(dp[i]\), 각 전이가 상수 → \(O(N)\).
- 2차원 상태 \(dp[i][j]\), 전이 상수 → \(O(NM)\).
단순 재귀의 지수 시간이, 메모이제이션으로 "상태 수만큼만" 계산하게 되어 극적으로
줄어듭니다.
정리
DP는 "겹치는 작은 문제의 답을 저장해 재사용"하는 기법입니다. 상태를 정의하고,
점화식을 세우고, 순서대로 채웁니다. 상태 정의가 가장 중요하며, 이것이
Silver 이후 수많은 문제의 핵심 무기가 됩니다. 다음 강의에서 코드로 익힙니다.