csmoon1010의 SW 블로그

Dynamic Programming (동적 계획법) 본문

Coding Test/알고리즘

Dynamic Programming (동적 계획법)

csmoon1010 2020. 8. 7. 22:47

1. Dynamic Programming이란?

: 복잡한 문제를 "작은 문제"로 나누어 푸는 방법

- "작은 문제"에서 최적의 결과 전체의 최적의 결과

- 앞에서 구한 결과를 다음 계산 때 이용하는 방향 (재사용)

 

2. 방식

1) 하향식 알고리즘(Top-Down)

: 큰 문제에서 재귀함수를 호출하여 푸는 방식 "작은 문제"가 중복되어 풀림

ex> 막대 자르기 문제 : 어떻게 잘라야 최대 이익으로 팔 수 있는가(길이에 따라 가격 책정이 다름)

Function cutRod(p, n){
    if(n = 0) return 0;
    q <- p[n];
    for i = 1 to n-1 {
        q <- max{q, p[i] +  cutRod(p, n-i)};
    }
    return q;
}

- 한계 : 내부에 시스템 호출 stack을 사용하는 overhead 발생 가능

    상향식 : 계산한 결과를 memory에 저장하여 재사용

 

 

2) 상향식 알고리즘(Bottom-Up)

: 작은 문제부터 풀기 시작 큰 문제를 풀 때 참조하는 작은 문제들의 결과가 이미 구해진 상태

ex> 막대 자르기 문제

Function bottomUpCutRod(p, n){
    r[0] <- 0;
    for j = 1 to n{
        q <- -inf;
        for i = 1 to j {
            q <- max{q, p[i] + r[j-i]};
        }
        r[j] <- q;
    }  
    return q;
}

 

3. 알고리즘 구상 방향

- 작은 문제들의 최적값이 전체의 최적값과 연관성이 있는지 확인

- 재귀적인 성질(재귀 함수, 앞에서 계산한 값을 재사용) 활용

- Memoization_메모리에 저장 : 중복 계산은 최대한 피하는 방향

 

4. 예시

(1) 피보나치 수를 구하는 함수

- 과정

1. 문제를 부분 문제로 분할
Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)
Fibonacci(n-1) = Fibonacci(n-2) + Fibonacci(n-3)
...
Fibonacci(2) = Fibonacci(1) + Fibonacci(0)

2. 가장 작은 부분 문제부터 해 구하기

3. 결과를 테이블에 저장하고, 저장된 부분 문제의 해를 이용해 상위 문제의 해 구하기(Memoization)

- 상향식 알고리즘

public int fibonacci(int n){
    int[] f = new int[n+1];
    f[0] = 0; f[1] = 1;
    for(int i = 2; i <= n ; i++){
        f[i] = f[i-1] + f[i-2];
    }
    return f[n];
}
Comments