背包问题九讲的总结

0/1背包问题

0/1背包的问题在于每个物品只有1件,每件物品只能选择放或者不放,于是就有了动态规划的解法:

for(int i = 1; i <= m; ++i) {
            for(int j = 1; j <=n j++) {
	            f[i][j]=max(f[i−1][j],f[i−1][j−c[i]]+w[i])
            }
 }

f[i][j] 表示 前i个物品放到容量为j的背包的最大价值,直接聊聊优化空间的事情,这里注意表达式,我们要优化的就是表达式中的一维数组,也就是i所在的坐标,从表达式可以看到这里只要保证求解i个物品时,i-1个物品的状态没变就行,怎么让这个状态不变呢?那就只能是更新物品时逆序更新,这样每一轮的更新物品后,

​for (int i = 1; i <= n; i++)
    for (int j = V; j >= 0; j--)
        f[j] = max(f[j], f[j - c[i]] + w[i]);

上述代码的意思就是:容量为j的袋子可以放的最多价值的物品,当j从V到0的时候,放第一个物品,每个容量可以最多价值f(j),最后不停的增加物品,来更新f(j)的值。

完全背包问题

题目:有N 种物品和一个容量为V的背包,每种物品都有无限件可用。第i 种物品的费用是c [ i ] ,价值是w [ i ] 。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

那么还是回到二维数组的转移法方程:

f[i][j]=max(f[i−1][j−k∗c[i]]+k∗w[i])   ∣0≤k∗c[i]≤j

这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。我们继续改进这个复杂度。这里唯一的特点就是物品可以无限取,所以我们将容量为V的背包除以每一个物品的重量,这样可以得到该物品最多可以装进背包的个数,然后这个问题就变为了0/1背包问题,只不过物品数目增加了,然后就利用0/1背包的公式来求解,

​for (int i = 1; i <= n; i++)
    for (int j = V; j >= 0; j--)
        f[j] = max(f[j], f[j - c[i]] + w[i]);

公式没变,物品数量变多。

关于二进制提高速度

其实主要思想是减少相同物品的数量,比如背包容量为10,有一个物品中重量为1,价值为2,可以选择这个物品10个,得到价值20,如果把这个物品扩展到10个,形成0/1背包问题,那么物品数量有点多,那么有没有减少物品数量的办法,不需要10个相同的物品呢?这时候就采取二进制方法,利用二进制的特点,减少物品数量,比如111这个二进制数,表示的是7,第一个1表示4,第二个1表示2,第三个1表示1,那么由这三个物品,1、2、4就可以组合成0~7的所有数字,也就是需要1、2、4、8就可以满足10个物品的组合,根本不需要10个重量为1、价值为2的物品,只需要4个物品,分别是:

  • 重量为1,价值为2
  • 重量为2,价值为4
  • 重量为4,价值为8
  • 重量为8,价值为16

这样也提高了速度。

参考博客

背包九讲——全篇详细理解与代码实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值