【动态规划】背包问题

三种背包问题定义

01背包:有N件物品和一个容量为C的背包,第i件物品消耗的容量为Wi,价值为Vi,求解放入哪些物品可以使得背包中总价值最大。

完全背包:有N种物品和一个容量为C的背包,每种物品都有无限件可用,第i件物品消耗的容量为Wi,价值为Vi,求解放入哪些物品可以使得背包中总价值最大。

多重背包:有N种物品和一个容量为C的背包,第i种物品最多有Mi件可用,每件物品消耗的容量为Wi,价值为Vi,求解入哪些物品可以使得背包中总价值最大。

从0-1背包开始

dp[i][w] 的定义如下:对于前 i 个物品,当前背包的容量为 w,这种情况下可以装的最大价值是 dp[i][w]。

那么dp[i][j]的最优解从哪里来呢,只有两种情况:要么不放第i个物品,此时的最优解=dp[i-1][j];要么放,此时的最优解=dp[i-1][j-Wi]+Vi。

由于dp[i][j]的值依赖左上方的值,所以整个表本来应该是从左到右,从上到下更新的。但是,其实我们只需要dp[i-1]就好了。但是在一维数组里操作会出现问题,当第i行的值覆盖掉了第i-1行的值怎么办呢?所以需要从右到左更新(只要知道dp[i-1],dp[i]的更新顺序是无所谓的)。

Python代码示例:

max_weight=int(input())
w = list(input().split(','))
v = list(input().split(','))
w = [int(each) for each in w]
v = [int(each) for each in v]
dp = [0]*(max_weight+1)
for i in range(len(w)):
    # 从右向左更新
    j=max_weight
    while j>=w[i]:
        dp[j] = max(dp[j],dp[j-w[i]]+v[i])
        j-=1
print(dp[-1])

扩展到完全背包

我们为了获取到上一次计算的值,我们选择从后往前计算,但是完全背包正好相反,这才是它需要的,完全背包因为需要累计多个同一物品的值,前一次计算可能是1个、2个等等,下一次j变化了以后,计算的可能是3个或者更多,所以我们需要保存实时计算出来的多个同一物品的最大价值,我们选取从前往后的顺序,这样每次前面计算的我们都可以在j增大以后累加获得更多个同一物品的最大价值。

你可能感兴趣的:(【动态规划】背包问题)