Skip to content

Commit 78b4306

Browse files
author
zhangheng
committed
add 0/1 Knapsack Problem
1 parent f56bc30 commit 78b4306

File tree

9 files changed

+161
-1
lines changed

9 files changed

+161
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
6. [动态规划](./doc/Dynamic_Programming/readme.md)(基本概念)
1212
7. 最长公共子序列(动态规划练习题)
1313
8. [最优二叉搜索树](./doc/Dynamic_Programming/optimal_binary_search_tree.md)
14-
9. 0-1背包问题
14+
9. [0-1背包问题](./doc/Dynamic_Programming/0-1_knapsack_problem.md)
1515
10. 完全背包问题
1616
11. 多重背包问题
1717

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
public class KnapsackProblem_0_1 {
3+
private int[] vs = {0, 2, 4, 3, 7};
4+
private int[] ws = {0, 2, 3, 5, 5};
5+
private Integer[][] results = new Integer[5][11];
6+
7+
private int ks3(int i, int j) {
8+
9+
for (int m = 0; m <= i; m++) {
10+
results[m][0] = 0;
11+
}
12+
for (int m = 0; m <= j; m++) {
13+
results[0][m] = 0;
14+
}
15+
16+
for (int m = 1; m <= i; m++) {
17+
for (int n = 1; n <= j; n++) {
18+
if (n < ws[m]) {
19+
// 装不进去
20+
results[m][n] = results[m - 1][n];
21+
} else {
22+
// 容量足够
23+
if (results[m - 1][n] > results[m - 1][n - ws[m]] + vs[m]) {
24+
// 不装该物品,最优价值更大
25+
results[m][n] = results[m - 1][n];
26+
} else {
27+
results[m][n] = results[m - 1][n - ws[m]] + vs[m];
28+
}
29+
}
30+
}
31+
}
32+
return results[i][j];
33+
}
34+
35+
36+
public static void main(String[] args) {
37+
KnapsackProblem_0_1 kp01 = new KnapsackProblem_0_1();
38+
int result = kp01.ks3(4, 10);
39+
System.out.println(result);
40+
}
41+
}
42+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# 动态规划--0/1背包问题
2+
3+
## 介绍
4+
5+
给定**N个物品**,每个物品有**重量W****价值V**,你有一个能**装重量M的背包**,问怎么装使得**携带价值最大**,并且每个物品只有一个。
6+
7+
**上面这个题干有以下这些故事:**
8+
9+
* 山洞的宝藏
10+
* 超市大赢家
11+
* RPG游戏回城卖垃圾
12+
13+
直观上,我们直观上会以贪心策略来求解这道题,所谓**携带价值最大**,实际上就是找性价比最高的一些东西塞包里面,这里性价比就是**价值/重量**,如果去抢商场,当然是去洗劫珠宝店,不然去抢超市,捎上两斤白菜么?
14+
15+
但是,贪心策略给出的结论不一定是最优解,比如给出下面这个清单,尝试使用贪心策略来装货试试。
16+
17+
| 编号 | 价值 | 重量 | 性价比 |
18+
| :--: | :--: | :--: | :--: |
19+
| A | 9 | 3 | 3 |
20+
| B | 7 | 2 | 3.5 |
21+
| C | 1 | 1 | 1 |
22+
23+
现在给定一个负重为3的背包,从性价比的倒序排列,先把性价比最高的B先塞包里,然后再拿个C填剩下的空缺。但是这个明显不是最优策略,就拿一个A的价值是最高的。
24+
25+
| 组合 | 重量 | 价值 |
26+
| :--: | :--: | :--: |
27+
| B+C | 3 | 8 |
28+
| A | 3 | 9 |
29+
30+
对于最优解,怎么做?
31+
32+
## 最优解
33+
34+
还是前面这个例子,我们先做一个穷举求解,对于很多人而言,没有什么是不能暴力的,如果不能,加机器 =,=
35+
36+
| idx | ABC | 重量 | 价值 |
37+
| :--: | :--: | :-------: | :------: |
38+
| 0 | 000 | 0+0+0 = 0 | 0+0+0 = 0 |
39+
| 1 | 001 | 0+0+1 = 1 | 0+0+1 = 1 |
40+
| 2 | 010 | 0+2+0 = 2 | 0+7+0 = 7 |
41+
| 3 | 011 | 0+2+1 = 3 | 0+7+1 = 8 |
42+
| 4 | 100 | 3+0+0 = 3 | 9+0+0 = 9 |
43+
| 5 | 101 | 3+0+1 = 4 | 9+0+1 = 10 |
44+
| 6 | 110 | 3+2+0 = 5 | 9+7+0 = 16 |
45+
| 7 | 111 | 3+2+1 = 6 | 9+7+1 = 17 |
46+
47+
3个物品跑了8次,40个物品得计算1 0995 1162 7776次。一桌子的东西出个方案给算了一年,废物!
48+
49+
**我们来优化一下。**
50+
51+
大家应该看出来很多计算压根就是多余的,比如第5个101就已经不用计算了,第4个就已经把包装满了。
52+
53+
下面这个张图是对前面表格计算的优化,在是否添加下一个物品的时候添加一条判断策略:**添加的物品是否已经超重**
54+
55+
![](../../res/Dynamic_Programming/kp1.png)
56+
57+
## 动态规划
58+
59+
动态规划有个基本思考方法,是将大问题拆解,对解空间的“所有”方案进行了比对,并分阶段去决策处理,通过对过程进行"剪枝",实现优化。
60+
61+
0/1背包问题好像符合动态规划的基本特征:有分支处理,有重复处理,搜索最优解;这里需要找到0/1背包问题的阶段、状态和状态转移,这里悬而不论。
62+
63+
作为动态规划最重要的问题,是要回答最优解的子问题是否也是最优解,也称为**最优化原理**
64+
65+
抛开上述问题,我们想象一下装包流程:
66+
67+
如果只有一件物品,那当然只要包能装得下,这个物品自然就是最优解。
68+
69+
再添加一件物品,如何获得最优解?这个就要考虑现在背包剩余空间够不够,如果不够,往外腾出足够的空间放进去,和不放这件物品相比哪个更好?
70+
71+
![](../../res/Dynamic_Programming/kp2.png)
72+
73+
归纳一下,放一件物品的最优解:
74+
75+
* 背包剩余空间足够(放进去当然比不放要贵重),够则放;
76+
* 剩余空间不够,腾出刚好足够的空间把这个物品放进去和当前的最优解相比,大则放;
77+
78+
推导**状态转移方程**
79+
80+
对于添加的第i个物品,背包空间有w个单位。有c[i,w]为最优解。如下数学函数中:
81+
82+
* 当物品数量或者背包容量为0时,最优价值为0;
83+
84+
* 当物品重量大于背包总空间则以添加前的结果为最优;
85+
* i的价值加上将背包腾出足够的空间的价值之和,与添加前的价值,取大者为最优;
86+
87+
![](../../res/Dynamic_Programming/kp3.png)
88+
89+
## 二维记录表
90+
91+
有了前面对过程的拆解,后面模拟解题。下面给出一个稍微复杂一点的题设: v=[2,4,3,7], w=[2,3,5,5],背包负重为10。
92+
93+
![](../../res/Dynamic_Programming/kp4.png)
94+
95+
96+
97+
![](../../res/Dynamic_Programming/kp5.png)
98+
99+
![](../../res/Dynamic_Programming/kp6.png)
100+
101+
最优解是13
102+
103+
104+
105+
106+
107+
108+
109+
110+
111+
112+
113+
114+
115+
116+
117+
118+

res/Dynamic_Programming/kp1.png

36.6 KB
Loading

res/Dynamic_Programming/kp2.png

22.6 KB
Loading

res/Dynamic_Programming/kp3.png

36.2 KB
Loading

res/Dynamic_Programming/kp4.png

25.8 KB
Loading

res/Dynamic_Programming/kp5.png

48.2 KB
Loading

res/Dynamic_Programming/kp6.png

29.7 KB
Loading

0 commit comments

Comments
 (0)