동적 계획법(Dynamic Programming)은 큰 문제를 작은 문제로 나누고, 그 하위 문제들의 결과를 저장하여 반복 계산을 줄이는 문제 해결 패러다임이다.
기존의 단순한 재귀(Naive Recursion)는 같은 하위 문제를 여러 번 계산해서 불필요한 연산이 많다. 이를 방지하기 위해 이미 계산한 결과를 저장(Memoization)해 두고 재활용함으로써 성능을 극적으로 개선할 수 있다.
살을 내주고 뼈를 취한다는 전략처럼, 충분히 가치 있는 비용이다int combination(int n, int r)
{
if (r == 0 || n == r)
return 1;
return combination(n - 1, r - 1) + combination(n - 1, r);
}
int cache[50][50];
int combination(int n, int r)
{
if (r == 0 || n == r)
return 1;
int& ret = cache[n][r];
if (ret != -1)
return ret;
return ret = combination(n - 1, r - 1) + combination(n - 1, r);
}
int& ret = cache[n][r]로 참조하여 값 저장/재사용memset(cache, -1, sizeof(cache))로 처리 (계산 여부 판별)int main()
{
::memset(cache, -1, sizeof(cache));
__int64 start = GetTickCount64();
int result = combination(45, 6);
__int64 end = GetTickCount64();
cout << end - start << " ms" << endl;
}
| 방식 | 실행 시간 |
|---|---|
| 단순 재귀 | 359ms 이상 |
| 메모이제이션 | 0ms ~ 매우 빠름 |
| 조건 | 설명 |
|---|---|
| 최적 부분 구조 | 전체 문제의 해가 하위 문제들의 해로 구성될 수 있어야 한다 |
| 중복되는 하위 문제 | 동일한 하위 문제가 여러 번 등장함 |
| 캐시 가능 | 계산된 값을 저장하고 재사용 가능해야 함 |
기저 사례 정의:
캐시 초기화:
-1로 초기화캐시 확인 후 계산: