STUDY/[ 자료구조 ]

동적 계획법(Dynamic Programming, DP)

Lim임 2025. 12. 2. 13:58

동적 계획법(Dynamic Programming, DP)

DP, 즉 다이나믹 프로그래밍(또는 동적 계획법)은 기본적인 아이디어로 

하나의 큰 문제를 여러 개의 작은 문제로 나누어서 그 결과를 저장하여 다시 큰 문제를 해결할 때 사용하는 것으로

특정한 알고리즘이 아닌 하나의 문제해결 패러다임으로 볼 수 있다.

 

Richard Bellman이 1950년대에 사용한 단어로 이름은 그냥 멋있어 보여서 그렇게 지어졌으니 신경 쓰지 않아도 된다.
큰 문제를 작은 문제로 쪼개서 그 답을 저장해두고 재활용한다. 그래서 혹자는 DP가 아닌 '기억하며 풀기'라고 부르기도 한다.


동적 계획법의 핵심 개념


(1) 겹치는 부분 문제 (Overlapping Subproblems)

  • 큰 문제를 해결하는 과정에서 동일한 작은 문제들이 반복적으로 등장하는 구조를 의미한다.
  • 예: 피보나치 수열의 단순 재귀 → 같은 값 계산이 수없이 반복된다.

(2) 최적 부분 구조 (Optimal Substructure)

  • 큰 문제의 정답이 작은 문제들의 정답을 조합하여 만들어질 수 있는 성질이다.
  • 예: fib(n) = fib(n-1) + fib(n-2)

 

일반적인 재귀(Naive Recursion) 방식 또한 DP와 매우 유사하다.

큰 차이점은 일반적인 재귀를 단순히 사용 시 동일한 작은 문제들이 여러 번 반복 되어 비효율적인 계산될 수 있다는 것이다.

 

예를 들어 피보나치 수열을 살펴보자. 피보나치 수열은 아래와 같다.
1,  1,  2,  3,  5,  8,  13,  21,  34,  55,  89,  144 ...

피보나치 수를 구하고 싶을 때 재귀로 함수를 구성하면 어떻게 될까? 단순하다. return f(n) = f(n-1) + f(n-2)

그런데 f(n-1), f(n-2)에서 각 함수를 1번씩 호출하면 동일한 값을 2번씩 구하게 되고 이로 인해 100번째 피보나치 수를 구하기 위해 호출되는 함수의 횟수는 기하급수 적으로 증가한다.(약 7해, #,###경 #,###조 ... 번 이상 함수 호출, 컴퓨터도 죽는다.)

왜냐하면, f(n-1)에서 한 번 구한 값을 f(n-2)에서 또 다시 같은 값을 구하는 과정을 반복하게 되기 때문이다. 아래의 그림처럼 반복되는 계산을 또 하게 된다.

 

그러나 한 번 구한 작은 문제의 결과 값을 저장해두고 재사용 한다면 어떨까?

앞에서 계산된 값을 다시 반복할 필요가 없이 약 200회 내에 계산이 가능해진다.


동적 계획법의 두 가지 접근 방식


(1) Top-Down 방식 (Memoization)

  • 재귀를 사용하고, 필요할 때만 계산한 뒤 메모(memo)에 저장하여 중복 계산을 제거한다.

예시 코드:

function fib(n, memo = {}) {
if (n <= 1) return n;
if (memo[n]) return memo[n]; // 이미 계산했으면 재사용

memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
	return memo[n];
}

 

(2) Bottom-Up 방식 (Tabulation)

  • 반복문을 사용하여 작은 문제부터 테이블(dp 배열)을 채워가는 방식이다.

예시 코드:

function fib(n) {

const dp = [0, 1];

for (let i = 2; i <= n; i++) {
	dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}

 

dp[0] = 0
dp[1] = 1
dp[2] = dp[1] + dp[0] = 1
dp[3] = dp[2] + dp[1] = 2
dp[4] = dp[3] + dp[2] = 3
dp[5] = dp[4] + dp[3] = 5
dp[6] = dp[5] + dp[4] = 8

 

 

  • 재귀가 자연스러울 때 → Top-Down
  • 명확한 DP 테이블이 보일 때 → Bottom-Up
  • 성능 중요 + n이 크다 → Bottom-Up 권장 (스택 오버플로우 방지)

 

 


DP 문제인지 판단하는 법


1) 큰 문제를 작은 문제로 나눌 수 있는가?
2) 작은 문제들이 서로 겹치는가?
3) 큰 문제의 해답이 작은 문제의 해답을 조합해서 만들어지는가?

이 기준에 부합하면 DP 가능성을 고려할 수 있다.


대표적인 DP 문제 종류


  • 피보나치 수열
  • 계단 오르기
  • 최대 부분합 (Kadane Algorithm)
  • 동전 교환 문제
  • 배낭 문제 (Knapsack)
  • 최장 증가 부분 수열 (LIS)
  • 최장 공통 부분 수열 (LCS)

정리

동적 계획법은

  • 큰 문제를 반복되는 작은 문제로 쪼개고
  • 계산된 결과를 저장하여 재사용함으로써
  • 시간 복잡도를 크게 줄이는 알고리즘 기법이다.

DP 배열 정의 → 점화식 세우기 → 초기값 → 계산
이 프로세스를 익히면 대부분의 DP 문제를 해결할 수 있다.

'STUDY > [ 자료구조 ]' 카테고리의 다른 글

그리디 알고리즘  (0) 2025.11.25
그래프  (0) 2025.11.18
트리  (0) 2025.11.12
검색, 탐색 알고리즘  (0) 2025.11.04
[자료구조] 스택 큐  (0) 2025.10.14