0verview 다이나믹 프로그래밍

3 minute read

다이나믹 프로그래밍

개요

다이나믹 프로그래밍
      
      ├─ 패러다임
           
        분할정복: 중복된 하위 분제들 and 최적 부분 구조
        
      └─ 방법론
            하향식 접근법: 메모이제이션
            상향식 접근법: 타뷸레이션
  • 동적계획법이라고도 한다
    • 동적?
      • 시가변적(time-varing)
      • 다단계적(multistage)
  • 개념
    • 문제를 각각의 작은 문제로 나누어 해결
    • 해결한 결과를 저장
    • 저장된 결과를 나중에 큰 문제의 결과와 합하여 풀이
  • 최적 부분 구조(Optimal Substructure) 갖는 문제 풀이 가능
    • 최적 부분 구조(Optimal Substructure)? 문제의 최적 해결 방법이 부분 문제에 대한 최적 해결 방법으로 구성되는 경우의 문제

다이나믹 프로그래밍 vs 그리디 알고리즘

동적계획법 그리디
가능한 모든 방법 고려 그 순간에 최적인 방법 고려
항상 최적 항성 최적 아니다

다이나믹 프로그래밍 vs 분할 정복

  • 둘 다 큰 문제를 작은 문제로 분할한다는 점에서는 같지만, 분할되는 부문 문제에서 차이가 있다
동적계획법 분할정복
부분 문제가 중복되고 공유된다 서로 겹치지 않는(disjoint) 부분 문제로 분할

알고리즘과 풀이 가능한 문제들의 특징

알고리즘 풇이 가능한 문제들의 특징 풀이 가능한 문제 및 알고리즘
동적계획법 최적 부분 구조, 중복된 하위 문제들 0-1(분할 불가) 배낭 문제, 피보나치 수열, 다익스트라 알고리즘
그리디 최적 부분 구조, 탐욕 선택 속성 분할 가능 배낭 문제, 다익스트라 알고리즘
분할정복 최적 부분 구조 병합 정렬, 퀵 정렬

다이나믹 프로그래밍 패러다임

최적 부분 구조

  ┌──────300 km────┐ ┌──120 km───┐
서울─────200 km────대구──80 km──부산
  └──────250 km────┘ └──100 km───┘
  • 최단 경로는? 200 + 80 = 280
    • 서울에서 대구까지 가는 최단 경로 문제
    • 대구에서 부산까지 가는 최단 경로 문제
  • 즉, 문제의 최적 해결 방법 = 부분 문제에 대한 최적 해결 방법으로 구성
    • 이러한 구조를 최적 부분 구조라 한다
  • 반면 서울 - 부산 새로운 고속도로가 새통되면 굳이 대구를 거칠 필요가 없으며, 그때는 더이상 최적 부분 구조가 아니다.

중복된 하위 문제(Overlapping Subproblem)

  • 피보나치 수열
f(5) = f(4) + f(3) = 5
              
              f(3) = f(2) + f(1) = 2
                            
                           f(1) = 1
                     f(2) = 1
        
        f(4) = f(3) + f(2) = 3
                      
                      
                     f(2) = 1
               
               f(3) = f(2) + f(1) = 2
                             
                            f(1) = 1
                       
                      f(2) = 1
  • f(5)를 계산하기 위해,
    • f(3)은 두번 중복
    • f(2)는 세 번 중복
    • f(1)은 두 번 중복

다이나믹 프로그래밍 방법론

상향식

상향식 개요

  • 타뷸레이션(Tabulation)이라 부른다
    • 데이터를 테이블 형태로 만들면서(Tabulate) 문제를 풀이 의미
  • Bottom-up
    1. 더 작은 하위 문제부터 살펴본 다음
    2. 작은 문제의 정답을 이용해 큰 문제의 정답을 풀어나간다
  • 일반적으로 이 방식만을 다이나믹 프로그래밍으로 지칭하기도 한다

상향식 예제

def fib_bottom_up(n):
    dp = []
    dp[0] = 0
    dp[1] = 1

    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i -2]

    return dp[n]
function fib_tabulation(num) {
  const table = {};
  table[0] = 0;
  table[1] = 1;
  for (let i = 2; i < num + 1; i++) {
    table[i] = table[i - 1] + table[i - 2];
  }
  return table[num];
}

하향식

하향식 개요

  • 메모이제이션(Memoization)이라 부른다
    • 클래스 필드 등을 사용하지 않고, 결과 값이 함수의 입력 값(파라미터)에 의해서만 결정되는 참조적 투명 함수(referential transparent function)에만 적용 가능
    • 이미 풀어봤는지 확인하여 재활용하는 효율적 방식
    • 이전 풀이를 메모해 둠을 의미
  • Top-Down
    1. 하위 문제에 대한 정답을 계산했는지 확인해가며
    2. 문제를 자연스러운 방식으로 풀어나간다

하향식 예제

def fib_top_down(n, dp):
    if n <= 1:
        return n
    
    if n in dp:
        return dp[n]
    
    dp[n] = fib_top_down(n - 1, dp) + fib_top_down(n - 2, dp)

    return dp[n]
// call stack이 지수적으로 증가한다
function fib_memoization(num, memo) {
  if (num <= 1) return num;
  if (memo.hasOwnProperty(num)) return memo[num];

  memo[num] = fib_memoization(num - 1, memo) + fib_memoization(num - 2, memo);

  return memo[num];
}

다이나믹 프로그래밍 알고리즘 설계

  1. 최적해의 구조의 특징을 찾는다
  2. 최적해의 값을 재귀적으로 정의한다
  3. 최적해의 값을 일반적으로 상향식 방법으로 계산
  4. 계산된 정보들로부터 최적해를 구성

최적해의 구조의 특징 찾기

재귀적으로 완전 탐색 알고리즘 만들기

하향식 또는 상향식 방법으로 계산

Updated: