빠에야는 개발중

다이나믹 프로그래밍 본문

공부/알고리즘

다이나믹 프로그래밍

빠에야좋아 2018. 2. 17. 20:12

다이나믹 프로그래밍은 “큰 문제를 작은 문제로 나누어 푸는 알고리즘”이다. 하지만 단순히 나누는 것이 다가 아니라, 두가지 조건을 만족해야만 다이나믹 프로그래밍으로 문제를 푼다고 할 수 있는데, 그 두가지는

 

  • Overlapping subproblem (겹치는 부분 문제)
  • Optimal substructure (최적 부분 구조)

이다.

Overlapping subproblem

겹치는 부분 문제란, “큰 문제를 작은 문제로 쪼갤 수” 있어야 하고, “큰 문제와 작은 문제를 같은 방법으로 풀 수” 있어야 한다는 것이다. 피보나치 수를 예로 들자면

 

f(0) = 0
f(1) = 1
f(n) = f(n-1) + f(n-2)

 

이런 식에서 f(n)을 구하는 문제는 다시 f(n-1)을 구하는 문제와 f(n-2)를 구하는 문제로 나누어진다. 상대적으로 작은 문제를 풀게 되는 것이다. 또한 같은 f( )를
구하는 것이므로 같은 방법으로 문제를 푼다고 할 수 있다.

Optimal substructure

최적 부분 구조란, 큰 문제의 정답을 작은 문제에서 구할 수 있어야 한다는 것이다.

위 피보나치 수의 식에서 f(n-1)은 다시 f(n-2) + f(n-3)이 되고, 이 때 f(n-2)가 중복이 된다. 작은 문제의 답을 “재활용”하여 큰 문제의 답을 구할 수 있는 것이다. 이 때, 후술할 메모이제이션이 사용된다. 그리고 최적 부분 구조를 만족한다면, 문제에 크기에 상관없이 어떤 한 문제의 답은 일정하다.

Memoization

다이나믹 프로그래밍에서 빠질 수 없는 것이 바로 메모이제이션이다. 메모이제이션은 말 그대로 “메모”하는 기법으로 부분 문제의 해를 메모하여 다음에 재사용하겠다는 것이다. 이 방식을 이용하면 겹치는 부분 문제를 여러번 계산할 필요 없이 자원을 아낄 수 있다.

 

* 추가 : Bottom-up 방식에서 사용하는 방법은 타뷸레이션(Tabulation)이라는 단어가 따로 존재한다고 한다. 메모이제이션은 Top-down 방식.

문제 접근 방법

다이나믹 프로그래밍의 접근 방법은 두가지로 나눌 수 있는데, Top-down 방식과 Bottom-up 방식이다.

Top-down

Top-down은 큰 문제를 쪼개가면서 해를 구하는 것이다. 주로 “재귀”를 이용해서 문제를 푼다. Top-down 방식을 사용하여 피보나치 수를 구하는 코드를 짜보자.

1
2
3
4
5
6
7
8
9
10
11
12
int dp[100];
int fibonacci(int n) {
    if(n <= 1) {
        return n;
    } else {
        if(dp[n] > 0) {
            return dp[n];
        }
        dp[n] = fibonacci(n-1+ fibonacci(n-2);
        return dp[n];
    }
}     
cs

Bottom-up

Bottom-up은 가장 작은 문제부터 해를 구하여 원래 문제의 해에 도달하는 것이다. 주로 “반복문”을 이용해서 문제를 푼다. Bottom-up으로 문제를 풀면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
int dp[100];
int fibonacci(int n) {
    dp[0= 0;
    dp[1= 1;
 
    for(int i = 2 ; i <= n ; i++) {
        dp[i] = dp[i-1+ dp[i-2];
    }
    return dp[n];
}    
cs

 

다이나믹 프로그래밍은 결국 내가 구하고자 하는 부분을 어떻게 메모할 지, 또 점화식을 어떻게 세울지에 따라 실력이 판가름 난다고 할 수 있다. 결국 많이 해보는 것이 중요하겠다.

'공부 > 알고리즘' 카테고리의 다른 글

해시 함수  (0) 2018.02.20
이진 탐색(binary search)  (0) 2018.02.16
Comments