[Algorithm] Dynamic Programming (DP)

1 minute read

python-version-3.7.1

Dynamic Programming (DP)

  • 여러개의 하위문제(Subproblem)를 통해 문제를 해결하는 알고리즘
  • ‘동적계획법’ 이라고 불린다.
  • Dynamic 에 특별한 의미는 없다.

Example

Fibonacci numbers

[0, 1, 1, 2, 3, 5, 8, 13, 21 . . .]

  • F0 = 0

  • F1 = 1

  • Fn = Fn-1 + Fn-2 (n >= 2)


Python Implementation Code

def fibo(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    return fibo(n-1) + fibo(n-2)

현재 코드는 중복 호출이 많아 비효율적이다.
이 문제를 해결하는 방법은 아래의 Approach 항목에서 다룬다.



Property

Overlapping Subproblem

  • 문제가 여러번 반복되는 하위문제로 나누어진다.

  • 하위문제 또한 반복되는 하위문제로 나누어지며 이를 통해 해를 구할 수 있다.
    (새로운 하위문제를 생성하지 않는다.)


alg-dp-fibo_recursive01


위의 이미지는 fibo(4) 를 실행했을 경우
재귀 호출되는 것을 이미지화한 것이다.
중복되는 함수호출을 표시해보면 아래와 같다.

alg-dp-fibo_recursive02

이를 통해 피보나치 수열은 반복되는 하위문제로 나누어짐을 알 수 있다.


Optimal Substructure

  • 하위문제의 최적해로 문제의 최적해를 구할 수 있다.

  • ex) 피보나치의 수열: Fn = Fn-1 + Fn-2 (n >= 2)



Approach

Memoization (Top-Down)

중복되는 함수 호출을 방지하기 위해
임의의 메모리에 해당 값들을 저장한 뒤 필요할 때 호출하는 방식


Property

  • 일반적으로 재귀를 사용한다.

  • 많은 재귀 호출로 인해 상대적으로 속도가 느리다.

  • 상대적으로 코드가 간결하다.


Python Implementation Code

Use dict
d = {0:0, 1:1}  # Define tmp dict for Memoization
def fibo(num):
    if num not in d.keys():
        d[num] = fibo(num-1) + fibo(num-2)  # Memoization
    return d[num]



Tabulation (Bottom-Up)

최하위 문제의 해부터 순차적으로 구하여 최종 문제의 해를 구하는 방법


Property

  • 일반적으로 반복문을 사용한다.

  • 많은 조건이 주어질 경우 상대적으로 코드가 복잡해진다.


Python Implementation Code

Use list
# 1
def fibo(n):
    d = [0, 1]
    for i in range(2, n+1):
        d.append(d[i-1] + d[i-2])
    return d[n]
# 2
def fibo(num):
    d = [0] * (num+1) if num > 0 else [0, 0]
    d[0] = 0
    d[1] = 1
    for i in range(2, num+1):
        d[i] = d[i-1] + d[i-2]
    return d[num]


Use dict
def fibo(n):
    d = {0:0, 1:1}
    for i in range(2, n+1):
        d[i] = d[i-1] + d[i-2]
    return d[n]

Leave a comment