DP
Updated:
- 분할정복은 하향식 dp는 상향식 방법으로 접근
문제제시 : 계수 값 구하기
-
이항계수 구하는 공식 (n k) = n!/k!(n-k)! for 0<= k<=n
- 계산량이 많은 n!이나 k!을 계산하지 않고 이항계수를 구하기 위해서 통상 다음 수식을 사용한다. (n k) = {if 0<k<n => (n-1 k-1) + (n-1 k) if k=0 or k=n => 1) nCk = n-1Ck-1 + n-1Ck
- 동적 계획법을 적용한 이항계수 계산
bino(n, k) B[][] FOR i in 0 -> n FOR j in 0 -> minimum(i,k) IF j=0 OR j=i B[i][j] <- 1 ELSE B[i][j] <- B[i-1][j-1] + B[i-1][j] RETURN B[n][k]
##0-1 Knapsack 알고리즘
문제제시 : 생일선물
- 배낭문제는 n개의 물건과 각물건 i의 무게 w와 가치 v가 주어지고 배낭의 용량은 w일때, 배낭에 담을 수 있는 물건의 최대 가치를 찾는 문제이다. 단, 배낭에 담은 물건의 무게의 합이 w를 초과하지 말아야 하고, 각 물건은 1개씩만 있다.
- 배낭문제를 DB로 접근해보자
- 먼저 배낭 문제의 부분 문제를 찾아내기 위해 문제의 조어진 조건을 살펴보면
- 물건, 물건의 무게, 물건의 가치, 배낭의 용량 모두 4가지의 요소가 있다.
- 이중에서 물건과 물건의 무게는 부분 문제를 정의하는데 반드시 필요하다.
- 왜냐하면 배낭이 비어있는 상태에서 시작하여 물건을 하나씩 배낭에 담는 것과 안 담는 것을 현재 배낭에 들어 있는 물건의 가치의 합에 근거하여 결정해야 하기 때문이다.
- 또한 물건을 배낭에 담으려고 할 경우에 배낭 용량의 초과 여부를 검사해야 한다.
- 따라서 배낭문제의 부분문제를 아래와 같이 정의할 수 있다.
- W= 배낭의 용량(KG)
- (v,w) = 가치(만원), 무게(kg)물건
- k[i,w] = 물건 1~i까지만 고려하고, (임시)배낭의 용량이 w일때의 최대 가치 단, i=1,2,…,n이고, w=1,2,3..W이다.
- K[i,w]를 개쥐겆ㄱ으로 정리하면
- if i=0 or w =0 => 0
- if wi => w K[i-1, w]
- if i>- and wi <= w => max(v + K[i-1, w-w], K[i-1,w])
- 배낭 문제의 부분 문제간의 함축적 순서는 다음과 같다.
- 즉, 2개의 부분 문제 K[i-1, w-w]가 K[i-1,w]가 미리 계산되어 있어야만 K[i,w]를 계산할 수 있다.
배낭의 용량 w
n개의 물건가 각 물건 1의 무게 wi와 가치 vi, 단, i=1,2,...,n
K[n, W]
FOR i in 0 -> n : K[i,0] <- 0
FOR w in 0 -> W : K[0,w] <- 0
FOR i in 1 => n
FOR w in 1-> W
IF wi > w
K[i,w] <- K[i-1,w]
ELSE
K[i,w] <- max(vi + K[i-1, w-wi], K[i-1,w])
RETURN K[n,W]
import java.util.Scanner;
public class DP3_KnapsackTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int W = sc.nextInt();
int[] weights = new int[N+1];
int[] profits = new int[N+1];
for(int i=1; i<=N; i++) {
weights[i] = sc.nextInt();
profits[i] = sc.nextInt();
}
int[][] D = new int[N+1][W+1];
for(int i=1; i<=N; i++) {
for(int w = 1; w<=W; w++) {
if(weights[i]<=w) {
//해당 물건을 가방에 넣을 수 있다.
D[i][w] = Math.max(D[i-1][w], profits[i] + D[i-1][w-weights[i]]);
}else {
//해당 물건을 가방에 넣을 수 없다.
D[i][w] = D[i-1][w];
}
}
}
System.out.println(D[N][W]);
}
}
Leave a comment