0-1背包
0-1 背包问题
问题:
给定一组商品和价值
物品 | 体积 | 价格 |
---|---|---|
物品1 | 3 | 6 |
物品2 | 4 | 7 |
物品3 | 5 | 8 |
物品4 | 6 | 9 |
物品5 | 7 | 10 |
现有背包20, 求拿的最高的价值。
思考
* 每件物品有取和不取的选择。
* 所有问题都通过子问题求解(递归思想)
* 根据动态规划思维(将子问题结果存起来):
问题拆分:
1. 可以将 背包容量拆分
2. 拆分物体个数
得出以下图
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | |||||||||||||||||||||
物品1 | |||||||||||||||||||||
物品2 | |||||||||||||||||||||
物品3 | |||||||||||||||||||||
物品4 | |||||||||||||||||||||
物品5 |
在不同体积下,不同个数的物品找最大值。
创建列表: v[k][w]
k 代表选[0 ---- k] 件商品, w代表背包容量
例如: v[5][3]
在前5件商品中取出,背包容量为3的最大价值
推出面对 第k件时有一下情况
-
背包容量不够
value_max =
v[k-1][w]
# 就是在 0----k-1 件中, 且背包容量为 w的最大价值-
背包容量够
- 不取
value_max1 =
v[k-1][w]
# 就是在 0----k-1 件中, 且背包容量为 w的最大价值- 取
value_max2 =
v[k-1][w-kw] + Vw
# 要查看 在 背包容量为 w - kw 的情况下 0 到 k-1件商品中最高价值 加上 当前商品的价值。 因为 要腾出容量存当前物体 例如: 看容量20时,取第五件的价值需要:(5件商品 体积7 价值10)
容量为 20 -1 = 13 时: 0-4 的最高价值 即
B[4][13]+ 10
最终决定取不取就是 max(value_max1,value_max2 ) 看哪个大。
-
代码实现:
def get_max(cap):
B = [[0 for i in range(cap+1)] for i in range(len(W))]
for k in range(0, len(W)): # 物品个数
for w in range(0, cap+1): # 背包容量
if W[k] > w: # 如果第n 个的体积大于背包容量
B[k][w] = B[k-1][w] # 0-k 里最大价值就是 在背包容量为 w时 0 到 k-1 件商品内的最大价值
else: # B[k-1][w-W[k]] + V[k] 查看 在 背包容量为 w - kw 的情况下 0 到 k-1件商品中最高价值 加上 当前商品的价值。 因为 要腾出容量存当前物体
B[k][w] = max(B[k-1][w-W[k]] + V[k], B[k-1][w]) # 应该时取和不取两种情况下的最大值
return B[len(W)-1][cap], B
result, B = get_max(20)
pprint.pprint(B)
# 假如说我要知道有哪些物品, 如果 B[k][cap] == B[k-1][cap-W[k]] + V[k] 说明这件物品找到了, 接下来就应该看,容量为 cap-W[k] 背包的选物情况了。 不等于的话说明这件没取到, 就看下一件
def get_items(cap, B):
for k in range(len(W)-1, 0, -1):
while cap > 0:
if B[k][cap] == B[k-1][cap-W[k]] + V[k]:
# 说明第k件取到了
print(k)
cap = cap-W[k]
break
get_items(20, B)