转载出处:http://blog.csdn.net/luoshixian099/article/details/46572285
背包问题
小偷发现了n个商品,第i个商品重量为
wi
,价值为
vi
。小偷希望尽量拿走价值高的商品,但是他的背包只能容纳W重的商品。求如何取舍这些商品?
由于对一个商品,要么被拿走要么不被拿走,所以被称为0-1背包问题。
我们如果采取枚举法进行比较,将会有
2n
个情况,算法复杂度与n呈指数关系。
下面分析背包问题的性质:
动态规划
最优子结构
令
xi
=1,表示第i个商品被拿走,
xi
=0,表示第i个商品不被拿走。
则问题变为求
V=max∑ni=1xivi
约束条件为
∑ni=1xiwi≤W
,求最大值的
x1,x2,x3..xn
解;
对于第k个商品,决定是否装包,需要进行比较,如果拿装包即
xk=1
,求子问题
V′=max∑ni=1xivi(i≠k)
,约束条件为
∑ni=1xiwi(x≠k)≤W−wk
。如果不装包,
xk=0
,
V′′=max∑ni=1xivi(i≠k)
,约束条件不变
∑ni=1xiwi(x≠k)≤W
。比较
V′与V′′
大小。
自底向上求解方案
算法复杂度为O(nW)
令c[i][j]表示第1个商品到第i个商品中,背包容量为j的情况下,可获得的最大价值;
决定是否选择商品i的方案,比较选与不选的获得的价值
c[i][j] = max(c[i-1][j] ,v[i]+c[i-1][j-w[i]])
例:
- 1
- 2
- 3
- 4
采用自底向上求解方案,先填写第一行c[1][j],此时只有商品1可选,当
j<w[1]
时,背包容量小于商品1的大小,所以c[1][j] =0,当
j≥w[1]
时,背包内价值即为商品1的价值c[1][j] = v[1]=4;
填写第二行:c[2][j],此时可选商品为1和2 。当
j<w[2]
,商品2一定装不了,但可能装下商品1,所以即c[2][j] = c[1][j],当
j≥w[2]
,此时可以装下商品2,如当j=6时,如果选择商品2,那么此时背包容量为j-w[2]=0,留给商品1用,而c[1][0]=0,所以背包价值为c[2][6]=v[2]+c[1][0];如果不选商品2,则c[2][6]=c[1][6]=4,比较大小得到,应该把商品2装包。即c[2][6]=v[2]+c[1][0]=6+0=6;
又如:当j=10时,如果选择商品2,则背包容量还剩j-w[2]=4;而c[1][4]=4,此时背包总价值为c[2][10]=v[2]+c[1][4]=6+4=10;如果不选商品2,c[2][10] =c[1][10]=4;选取最大值即c[2][10]=10;
按照上述方式自底向上填写表格:
构造最优解
按照上面描述:如果c[i][j] = c[i-1][j],表明商品i没有被选择;否则就被选择
从表格的右下端开始,即c[5][10],回溯。
如
c[5][10]≠c[4][10]
则商品5被选择,而此时背包容量j-w[5]=4;继续向上回溯,比较c[4][4]=c[3][4],表明商品4不选。回溯到第一个商品时,如果
c[1][j]≠0
,表明被装包;
完整代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88