0-1 Knapsack
๋๋์ด ๋ณด์๊ฐ๊ฒ์ ๋ฐฐ๋ญ์ ๋ฉ๊ณ ์นจ์
ํ๋ค.
๋ฐฐ๋ญ์ ์ต๋ ์ฉ๋์ W์ด๋ฉฐ, ์ด๋ฅผ ์ด๊ณผํด์ ๋ณด์์ ๋ด์ผ๋ฉด ๋ฐฐ๋ญ์ด ์ฐข์ด์ง ๊ฒ์ด๋ค.
๊ฐ ๋ณด์๋ค์ ๋ฌด๊ฒ์ ๊ฐ๊ฒฉ์ ์๊ณ ์๋ค.
๋ฐฐ๋ญ์ด ์ฐข์ด์ง์ง ์๋ ์๋ ์ ์์ ๊ฐ๊ฒฉ ํฉ์ด ์ต๋๊ฐ ๋๋๋ก ๋ณด์์ ๋ด๋ ๋ฐฉ๋ฒ์?
์๊ฐํ ์ ์๋ ์ํ์ฐฉ์ค
1) ๋ชจ๋ ๊ฒฝ์ฐ์ ์๋ฅผ ๋ฃ์ด๋ณธ๋ค (Brute-Force)
n๊ฐ์ ๋ณด์์ด ์๋ค๊ณ ์น๋ฉด, n๊ฐ ๋ณด์์ผ๋ก ๋ง๋ค ์ ์๋ ๊ฐ๋ฅํ ๋ถ๋ถ์งํฉ (power set) ์ ์๋ 2^n๊ฐ์ด๋ค. ์ต์
์ ๊ฒฝ์ฐ์ 2^n๋ฒ๊น์ง ๋ด์ผ ํ๋, ์ฆ O(2^n) ์ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ฌด ๋๋ฆฌ๋ค.
2) ๊ฐ๊ฒฉ์ด ๋์ ๋ณด์, ํน์ (๊ฐ๊ฒฉ/๋ฌด๊ฒ) ์ ๊ฐ์ด ์ ์ผ ๋์ ๋ณด์๋ถํฐ ๋จผ์ ๊ณจ๋ผ์ ๋ฃ๋๋ค (Greedy)
์๋์ ๊ทธ๋ฆผ์ ๋ณด์. ๊ฐ๊ฒฉ์ด ์ ์ผ ๋์ ๋ณด์์ ๋จผ์ ๊ณ ๋ฅด๋ ๋ฐฉ๋ฒ์ ์ด๋ค๊ณ ํ๋ฉด, ์ค๋ฅธ์ชฝ ์๋์ ์๋ ๋นจ๊ฐ ๋ณด์์ ๋จผ์ ๊ณ ๋ฅด๊ณ ๊ทธ ๋ค์ ์ผ์ชฝ์ ์๋ ๋
ธ๋ ๋ณด์์ ๊ณ ๋ฅผ ๊ฒ์ด๋ค. ๊ทธ๋ด ๊ฒฝ์ฐ์ ๊ฐ๊ฒฉ์ ์ดํฉ์ 16์ด ๋๋ค.
ํ์ง๋ง 1, 2, 3, 4์ ๋ฌด๊ฒ๋ฅผ ์ ํํ์์ ๋์ ๊ฐ๊ฒฉ์ ์ดํฉ์ 19๊ฐ ๋์ค๊ณ ๋จ์ํ๊ฒ ๊ฐ๊ฒฉ์ด ๋์ greedyํ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ์ ๋ ๋ต์ ๊ตฌํ ์ ์๋ค.
'๋ฌด๊ฒ๋น ๊ฐ๊ฒฉ'์ ๊ณ์ฐํด์ ์ ์ผ ๋์ ๊ฒ๋ถํฐ ์ง์ด ๋ฃ์ผ๋ฉด ์ฑ๋ฆฝํ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ ํ ์ ์๋ค. ์ค์ ๋ก ์์ ๊ทธ๋ฆผ์์๋ ๊ทธ๋ ๊ฒ ์ํํ๋ฉด ์ต์ ์ ๋ต์ด ๋์จ๋ค. ํ์ง๋ง ์ธ์ ๋ ๊ทธ๋ ์ง๋ ์๋ค. ์๋์ ์์๋ฅผ ๋ณด์
์ด ๊ฒฝ์ฐ์ '๋ฌด๊ฒ๋น ๊ฐ๊ฒฉ' ์์ผ๋ก ๋ณด์์ ๋ฃ์ผ๋ฉด ๋ณด์1, ๋ณด์3์ด ๋ค์ด๊ฐ๋ฉฐ ๊ฐ๊ฒฉ์ ํฉ์ 19์ด๋ค. ๊ทธ๋ฐ๋ฐ ๋ฐฐ๋ญ ๋ฌด๊ฒ๊ฐ 5๊ฐ ๋จ๋๋ค. ๋ณด์2๋ฅผ ๋ฃ์ ์๋ ์์ผ๋ฏ๋ก 5๋ ๊ทธ๋ฅ ์ธ๋ฐ์์ด ๋จ๋ ๊ณต๊ฐ์ด๋ค.
๋ณด์2, ๋ณด์3์ ๋ฃ์ผ๋ฉด 30๋ฌด๊ฒ๋ฅผ ๊ฐ๋ ์ฑ์ฐ๊ณ ๊ฐ๊ฒฉ์ ํฉ์ด 20์ด๋ค. ๋๋ ์
์ฅ์์ ๋๋ง๊ฐ ๋ ๋ฐฐ๋ญ์ด ์ข ๋ ๋ฌด๊ฑฐ์ธ ์ ์๊ฒ ์ง๋ง ์ด์จ๋ ๋ฌธ์ ์ ์กฐ๊ฑด์ ๋ฐฐ๋ญ์ด ์ ํฐ์ง๋ ํ๋ ๋ด์์ ๊ฐ๊ฒฉ ํฉ์ ์ต๋ํํ๋ ๊ฒ์ด๋ฏ๋ก ๋ณด์2, 3์ ๊ฐ์ ธ๊ฐ๋ ๊ฒ์ด ์ ๋ต์ด๋ค.
์ด์ฒ๋ผ ํน์ ํ ๊ธฐ์ค์ ์ ํด๋๊ณ ๊ทธ ๊ธฐ์ค์ ๊ฐ์ด ๊ฐ์ฅ ๋์ ์์ผ๋ก ์ง๋ ๊ฑธ Greedy ์๊ณ ๋ฆฌ์ฆ์ด๋ผ ํ๋๋ฐ 0-1 ๋ฐฐ๋ญ ์ฑ์ฐ๊ธฐ ๋ฌธ์ ๋ Greedyํ ๋ฐฉ๋ฒ์ผ๋ก๋ ํ ์ ์๋ ๋ฌธ์ ์ด๋ค.
Fractional Knapsack ๋ฌธ์ ๋ Greedy๋ก ํ ์ ์๋ค. ์ ์์์์ ๋ณด์2๋ฅผ ๋ฐ์ผ๋ก ์๋ผ์ ๋จ์ 5kg์ง๋ฆฌ ๊ณต๊ฐ์ ๋ฃ์ผ๋ฉด ๊ทธ๊ฒ ์ต์ ์ ๋ต์ด ๋๋ค
DP์ ์ ์ฉ
์ด๋ค ๋ฌธ์ ๋ฅผ DP๋ก ํ๊ธฐ ์ํด์๋ '์ต์ ์ ์๋ฆฌ' (Principle of Optimality) ๊ฐ ์ฑ๋ฆฝํ๋์ง๋ฅผ ํ์ธํด์ผ ํ๋๋ฐ, ์ต์ ์ ์๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ๋ค.
"์ด๋ค ๋ฌธ์ ์ ์
๋ ฅ์ฌ๋ก์ ์ต์ ํด๊ฐ ๊ทธ ์
๋ ฅ์ฌ๋ก๋ฅผ ๋ถํ ํ ๋ถ๋ถ์ฌ๋ก์ ๋ํ ์ต์ ํด๋ฅผ ํญ์ ํฌํจํ๊ณ ์์ผ๋ฉด, ๊ทธ ๋ฌธ์ ์ ๋ํ์ฌ ์ต์ ์ ์๋ฆฌ๊ฐ ์ฑ๋ฆฝํ๋ค."
์ด ๋ฌธ์ ์์ ์ด ์๋ฆฌ๊ฐ ์ฑ๋ฆฝํ ๊น? ์งํฉ A๋ฅผ n๊ฐ์ ๋ณด์๋ค ์ค์ ์ต์ ์ผ๋ก ๊ณ ๋ฅธ ๋ถ๋ถ์งํฉ์ด๋ผ๊ณ ๊ฐ์ ํ์.
โข
์งํฉ A๊ฐ n๋ฒ์งธ ๋ณด์์ ํฌํจํ๊ณ ์์ง ์๋ค๋ฉด, A๋ n๋ฒ์งธ ๋ณด์์ ๋บ ๋๋จธ์ง n-1๊ฐ์ ๋ณด์๋ค ์ค์์ ์ต์ ์ผ๋ก ๊ณ ๋ฅธ ๋ถ๋ถ์งํฉ๊ณผ ๊ฐ๋ค.
โข
์งํฉ A๊ฐ n๋ฒ์งธ ๋ณด์์ ํฌํจํ๊ณ ์๋ค๋ฉด, A์ ์ํ ๋ณด์๋ค์ ์ด ๊ฐ๊ฒฉ์ n-1๊ฐ์ ๋ณด์๋ค ์ค์์ ์ต์ ์ผ๋ก ๊ณ ๋ฅธ ๊ฐ๊ฒฉ์ ํฉ์๋ค๊ฐ ๋ณด์ n์ ๊ฐ๊ฒฉ์ ๋ํ ๊ฒ๊ณผ ๊ฐ๋ค. (๋จ, n๋ฒ์งธ ๋ณด์์ ๋ฃ์์ ๋ ๋ฐฐ๋ญ์ด ํฐ์ง์ง ์์์ผ ํ๋ค)
์ ํ์์ผ๋ก ํ์ด๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
P[i, w] ๋ i๊ฐ์ ๋ณด์์ด ์๊ณ ๋ฐฐ๋ญ์ ๋ฌด๊ฒ ํ๋๊ฐ w์ผ ๋ ์ต์ ์ ์ด์ต์ ์๋ฏธํ๋ค. ์์ ์ข ๋ฌธ์ฅ์ผ๋ก ํ์ด๋ณด๋ฉด ์ด๋ ๋ค.
โข
i๋ฒ์งธ ๋ณด์์ด ๋ฐฐ๋ญ์ ๋ฌด๊ฒ ํ๋๋ณด๋ค ๋ฌด๊ฑฐ์ฐ๋ฉด ๋ฃ์ ์ ์์ผ๋ฏ๋ก i๋ฒ์งธ ๋ณด์์ ๋บ i-1๊ฐ์ ๋ณด์๋ค์ ๊ฐ์ง๊ณ ๊ตฌํ ์ ๋จ๊ณ์ ์ต์ ๊ฐ์ ๊ทธ๋๋ก ๊ฐ์ ธ์จ๋ค
โข
๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, i๋ฒ์งธ ๋ณด์์ ์ํด i๋ฒ์งธ ๋ณด์๋งํผ์ ๋ฌด๊ฒ๋ฅผ ๋น์ ์ ๋์ ์ต์ ๊ฐ์ i๋ฒ์งธ ๋ณด์์ ๊ฐ๊ฒฉ์ ๋ํ ๊ฐ or i-1๊ฐ์ ๋ณด์๋ค์ ๊ฐ์ง๊ณ ๊ตฌํ ์ ๋จ๊ณ์ ์ต์ ๊ฐ ์ค ํฐ ๊ฒ์ ์ ํํ๋ค
ํ์ด ๊ณผ์
i == 0 || w == 0
๊ณ ๋ คํ๋ ๋ณด์์ด 0๊ฐ, ๋ฐฐ๋ญ์ ์ง์ด๋ฃ๋ ๋ฌด๊ฒ๊ฐ 0์ธ ์ํ์ด๋ค. ๋ชจ๋ 0์ผ๋ก๋งํนํ ์ํ์์ ์์ํ๋ค.
i == 1
i=1์ธ ๊ฒฝ์ฐ๋ถํฐ ํ์นธ์ฉ ๋ณด์. (i, w)๊ฐ (1, 1) ์ธ ๊ฒฝ์ฐ์๋ w=1์ง๋ฆฌ ๋ฐฐ๋ญ์ผ๋ก๋ ์๋ฌด ๋ณด์๋ ๋ฃ์ ์ ์์ผ๋ฏ๋ก 0์ด๋ค. ๊ทธ ๋ค์ ์นธ, (1, 2) ์ธ ๊ฒฝ์ฐ์๋ ์ด์ 1๋ฒ ๋ณด์์ ๋ฃ์ ์ ์์ผ๋๊น V[1, 2] = 3์ด ๋๋ค.
์ง๊ด์ ์ผ๋ก๋ ์ด๋ ๊ณ , ์์ ์์ ํตํด์ ๋ณด๋ฉด '1๋ฒ ๋ณด์์ ๊ฐ์น + V[0, 0]' ์ ๊ฐ๊ณผ V[0, 2] ์ ๊ฐ์ ๋น๊ตํด์ ๋ ํฐ ์ชฝ์ ๊ฐ์ ธ๊ฐ๊ฒ ๋๋๋ฐ, 1๋ฒ ๋ณด์์ ๊ฐ์น๋ 3์ด๊ณ V[0, 0] ๊ณผ V[0, 2] ๋ ๋ ๋ค 0์ด๋ฏ๋ก ์ ์๋ฅผ ์ ํํ๊ฒ ๋๋ค.
i == 2
i=2์ธ ๊ฒฝ์ฐ๋ฅผ ๋ณด๋ฉด, w=2์ผ๋๋ ํ์ฌ ๋ณด๊ณ ์๋ 2๋ฒ ๋ณด์ (3kg) ์ ๋ฃ์ ์ ์์ผ๋ฏ๋ก ๋ฐ๋ก ์์นธ์ 3์ ๊ฐ์ ธ์จ๋ค (1๋ฒ ๋ณด์์ ๋ฃ๋๋ค๋ ๋ป). w=3์ด ๋๋ฉด 2๋ฒ ๋ณด์์ ๋ฃ์ ์ ์๊ฒ ๋๋๋ฐ, 1๋ฒ ๋ณด์์ ๋ฃ์์ ๋ (๋ฐ๋ก ์์นธ) ๋ 2๋ฒ ๋ณด์์ ๋ฃ์๋งํผ์ ๊ณต๊ฐ์ ํ๋ณดํ๊ณ 2๋ฒ ๋ณด์์ ๋ฃ์์ ๋ (์ฆ, 2๋ฒ ๋ณด์์ ๊ฐ์น + V[1, 0]) ๋ฅผ ๋น๊ตํด์ ๋ ๊ฐ์น๊ฐ ๋์ ์ชฝ์ ์ ํํ๋ค. ๊ทธ๋์ 4๊ฐ ๋ค์ด๊ฐ๋ค.
๋ชจ๋ ๊ณผ์ ์ํ ์ดํ
์ฝ๋ ์์ฑ
public class FruitNotFoundException extends Exception {
public FruitNotFoundException(String name) {
super(name + "์ ํด๋นํ๋ ๊ณผ์ผ์ ์์ต๋๋ค.");
}
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][N+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];
}
}
}
}
}
Java
๋ณต์ฌ
0-1 knapsack์ 1์ฐจ์ ๋ฐฐ์ด ํ์ด
DP์ bottom-up์ ์ํฅ์ ํ์ด๋ก ํ์์ ๋ DP[w]์ ๊ฐ์ DP[w - i] ์ ๊ฐ์ ์ฐธ์กฐํ๋ฉฐ ์ฑ์์ง๊ฒ ๋๋ค. i๋ฒ์งธ ๋ณด์์ ์ฒ๋ฆฌ๋ฅผ ์ํํ๊ธฐ ์ํด์๋ i-1๋ฒ์งธ ๋ณด์๊น์ง์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํด์ผ ํ๋๋ฐ i๋ฒ์งธ ๋ณด์์ ์ฒ๋ฆฌ ๊ณผ์ ์์ i - 1 ๋ฒ์งธ ๊ฐ์ ๋ฎ์ด์์ด๋ค๋ฉด ์ฌ๋ฐ๋ฅธ ์ ๋ต์ ๊ตฌํ ์ ์๋ค.
๋ฐ๋ผ์ bottom-up ๋ฐฉ์์ ์ฌ์ฉํ๋ค๋ฉด 2์ฐจ์ ๋ฐฐ์ด์ ๊ด๋ฆฌํด์ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ์ฌ๋ฐ๋ฅธ ์ ๋ต์ ๊ตฌํ ์ ์๋ค.
ํ์ง๋ง top-down์ ํํฅ์ ํ์ด๋ก ํธ๋ ๊ฒฝ์ฐ์ ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
์์ฒ๋ผ n์ฐจ์ ๋ฐฐ์ด DP๋ฅผ n-1 ์ฒ๋ผ ์ต์ ํ ํ์ฌ ์ฌ์ฉํ๋ ๋ฐฉ์์ด ํ๋ก์ด๋-์์ฌ ์๊ณ ๋ฆฌ์ฆ์๋ ์ ์ฉ๋๋ค.