有一个背包,他的容量为w(Capacity)。现在有i中不同的物品,编号为0…n-1,
其中每一件物品的重量为w(i),价值为v(i)。问可以向这个背包中盛放哪些物品,
使得在不超过背包容量的基础上,物品的总价值最大。
动态转移方程:
把问题直接处理为“是否要装第i个物品的问题”。
dp[i][w]表示总共i个物品,包的限重为w的情况下,最大总价值量的解,那么这个问题的解只有两种可能,就是装入包中的物品中,包括了第i个物品和不包括第i个物品,最后选择的是装入的情况下的最优解,和不装入的情况下的最优解中,更优的那一个。
装入了第i个物品的情况:如果最优解是往包里装入了k个物品,其中最后一个就是第i个物品,那么去掉这个物品后,剩下的k-1个物品,就构成了dp[i-1][w-wi]的最优解(反正法:加入还有其他k-1个的总value更大,那加上第i个物品的总值也会更大)。所以,如果最优解中包括第i个物品,那么最优解就是dp[i-1][w-wi]+vi
没有装入第i个物品的情况:假如最优解往包里装的物品中不包括第i个物品,那么dp[i][w]就等价于dp[i-1][w],也就是要放到包里的物品,全部都来自前i-1个物品中。
以上分析的前提是基于,第i个物品的重量wi是在背包能承受的范围内的,假如wi>w,就直接排除第i个物品,最优解等于dp[i-1][w]
另外还要注意初始条件。
代码:
def backpack(weights, values, W):
I = len(weights) # 物品个数
dp = [[0 for i in range(W+1)] for i in range(I+1)]
if I*W ==0:
return 0
# 边界为0 ,所以从dp[1][1]开始
for i in range(1,len(dp)):
for w in range(1, len(dp[0])):
if weights[i-1]>w:
dp[i][w] = dp[i-1][w]
else:
dp[i][w] = max(dp[i-1][w-weights[i-1]]+values[i-1], dp[i-1][w])
return dp[-1][-1]
测试:
weights=[2,2,6,5,4]
values=[3,6,5,4,6]
backpack(weights, values, 10)
output:
15