背包九讲的深入理解

01背包问题:
简述:有N件物品,容量为V的背包,每一件物品的容量为c[i] 价值为 w[i] 问如何装物品 才能使在不超过背包容量的前提下,价值最大。
计:dp[i][j]表示最大装i个物品,此时背包的内存为j时的价值大小,很显然,j<=v;
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i])
这个转移方程的意思就是
如果第i个物品放入背包中时,那么前i-1个元素就要放入j-c[i]这个空间,如果第i个物品不放入背包时,那么i-1个元素就是要放入当前内存值j。
时间复杂度为o(nv) 空间复杂度也为o(nv)
//看了博客说这个可以不需要memset 其实也没事,o(n)的时间复杂度,但是一般题目memset还是要慎重使用的。
有时候也会卡空间复杂度,下面进行空间优化为o(v)
dp[j]=max(dp[j],dp[j-c[i]+w[i])
这个一维的转移方程搭配的就是将二维数组简化为一个双重的for循环。这是01背包的问题。
完全背包问题
完全背包与01背包的差别就在于完全背包是不限制个数的,我们所要讨论的问题就是不在于是否取这个物品了,而是在于取几件,0件,1件,2件,。。。。。
因此转移方程可以转变成
dp[i][j]=max(dp[i-1][j-kc[i]+kw[i])(0<=kc[i]<=V)
不需要考虑放或者不放,只需要考虑是否是否取。
将其优化的办法:
1.空间上减为一维,也就是说
d[j]=max(d[j-c[i])+w[i],d[j])//有待讨论
2.如果出现c[i]<=c[j],w[i]>=w[j]那么这个可以j可以直接去掉。//但是在实际过程中,不太容易执行,也就不怎么做考虑了。
写到这里,有两个疑问
1.疑问点,为什么01背包要使用倒叙
2.完全背包为什么能转换成不带k的一维方程。
问题1:经过我一天的理解,我大致知道了为什么需要逆序,
首先先来说一下,逆序和顺序的区别
顺序,每次从0更新到n,他更新的是什么呢,是以i物品为媒介的所有值,
然后到了i->i+1的状态时,他所更新的是i在i时刻的状态,而不是i-1时刻的状态,因此需要倒叙
举个例子吧 容量为10
物品 价值 重量
1 5 3
2 4 2
3 2 4
当i等于1时开始第一层循环:
顺序:
dp[1]=max(dp[1],dp[1-3]+5)=0;
dp[2]=0
dp[3]=5
dp[4]=max(dp[4],dp[4-3]+5)=5
dp[5]=5
dp[6]=max(dp[6],dp[6-3]+5)=10
dp[7]=max(dp[7],dp[7-3]+5)=10
dp[8]=max(dp[8],dp[5]+5)=10
dp[9]=max(dp[9],dp[6]+5)=15
dp[10]=15
乍一看没什么问题
但是你看dp[6],dp[6]=10,但是只能放一个物品不是吗,没有一个物品价值为10,所以显然顺序是错的。错就错在记录的状态不对。
那为什么完全背包就可以是正序的了呢。
首先来解释完全背包为什么能优化成一维的反向01背包。
首先正序的一维数组可以实现一件事物的多选,就比如上面的dp[6]=10,这就意味着正序的01背包可以实现多选,因此就符合01背包的正序实现了。
//终于解决了啊啊啊啊啊啊啊啊啊啊啊啊啊哭了
现在来看多重背包
多重背包与完全背包的区别就在于所有的东西不是随意的,总共有n[i]个,所以其实可以跟完全背包
dp[i][j]=max(dp[i-1][j-k
c[i]]+k*w[i] k是有范围的。
那么如何把他的空间复杂度降下来呢,
一方面我们可以通过o(n^3)的循环,来进行。
但是可以进行二进制优化,
这个二进制优化的原理就是我们可以把一件物品拆分成2n,和n[i]-2n个这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值