01背包和完全背包

  写在背包问题之前,我想说一下对循环顺序的理解。背包问题都会有备选集   ϕ   ~\phi~  ϕ 和限制数   N   ~N~  N    ϕ   ~\phi~  ϕ 是一个列表,   N   ~N~  N 是一个整数。循环顺序一般都是先关于备选集,再是关于限制数,解释为在   ϕ k = [ 1 , . . . , k ] , k ≤ N   ~\phi_k=[1,...,k],k\leq N~  ϕk=[1,...,k],kN    q ∈ [ 1 , . . . , N ]   ~q \in[1,...,N]~  q[1,...,N] 的条件下   f ( q , ϕ k )   ~f(q,\phi_k)~  f(qϕk) 的值,然后将   ϕ k   ~\phi_k~  ϕk 扩大成   ϕ k + 1   ~\phi_{k+1}~  ϕk+1 ,求   f ( ϕ k + 1 , q )   ~f(\phi_{k+1},q)~  f(ϕk+1,q) 的值,最后一直到求出   f ( ϕ , q )   ~f(\phi,q)~  f(ϕ,q) 的所有值,返回   f ( ϕ , N )   ~f(\phi,N)~  f(ϕ,N) 即可。
01背包问题
  01背包问题是经典的动态规划思想的一类问题,题目内容是有一个固定载重为 W W W的背包,另有 n n n种物品,每件物品具有两个属性,分别重量 w i w_i wi和价值 v i v_i vi。要求每种物品只能选择一次或者不选,问在不超过载重 W W W的情况下,装的物品的总价值最大为多少?
  分析问题:这里假定大家已经知道了这题的思路是动态规划!!!从上面的题目中可以看出,01问题就是就是“选”与“不选”的问题。即主要判断在满足载重限制的条件下,物品   i   ~i~  i 选择之后背包的总价值分析。
  设dp[ i i i][ j j j]表示前   i   ~i~  i 件物品在载重为   j   ~j~  j 的背包中的最大价值,下面来分析每个dp[ i i i][ j j j]的值该如何求得。

1、二维数组
每个物品只能选择一次或不选,物品i选择与否的条件是什么呢?
假设现在背包的状态是dp[ i i i-1][ j j j],即从前 { 1 , . . . , i − 1 } \{1,...,i-1\} {1...i1}个物品挑选物品加入载重为 { 1 , . . . , j } \{1,...,j\} {1...j}的背包中的所有组合已知。下一步需要选择是否将物品   i   ~i~  i 装入背包中,使得dp[ i i i][ j j j]最大,即从前   i   ~i~  i 个物品中挑选物品装入载重为   j   ~j~  j 的背包中,使在满足不超过载重   j   ~j~  j 的同时背包中的物品总价值最大。首先物品   i   ~i~  i 的重量不能超过载重   j   ~j~  j ,同时选择i物品之后背包的总价值比不选择物品   i   ~i~  i 时要大,即
for i i i in range(1,n+1):     #前 i i i个物品

#背包载重为   j   ~j~  j ,这里   j   ~j~  j 正序和倒序都行,因为dp是二维数组,dp[ i i i][:]的改变并不影响上一层状态dp[ i i i-1][:]
for j j j in range( w i w_i wi, W W W+1):

dp[ i i i][ j j j] = max ⁡ \max max{ dp[ i − 1 i-1 i1][ j j j] , dp[ i − 1 i-1 i1][ j − w i j-w_i jwi] + v i v_i vi } #dp[ i i i][ j j j] 为物品   i   ~i~  i 选择与否背包总价值较大者

  设dp[ j j j]表示载重为 j j j的背包中的物品最大价值,下面来分析每个dp[ j j j]的值该如何求得。

1、一维数组
考虑到上面二维数组中,物品   i   ~i~  i 选择与否只用到了第   i − 1   ~i-1~  i1 层的数据,所以可以将数组变成一维的情况。分析情况和二维一模一样,这里只是用一维数组表示背包总价值而已,降低了空间复杂度。
for i in range(1,n+1):     #前 i i i个物品

#背包载重为   j   ~j~  j ,这里   j   ~j~  j 必须倒序,因为dp是一维数组,这里要保证用到的dp[ i i i][:]和dp[ j − w i j-w_i jwi]是前一个状态的
for j in range( W W W w i w_i wi-1, -1):

dp[ j j j] = max ⁡ \max max{ dp[ j j j] , dp[ j − w i j-w_i jwi] + v i v_i vi } #dp[ j j j] 为物品   i   ~i~  i 选择与否背包总价值较大者

完全背包问题
  和01背包不同的是,完全背包中各种物品的选择可以是任意多的,即物品   i   ~i~  i 可以选择任意多次,然后同样是求背包的总价值最大。
  分析问题:在载重限制的条件下,物品   i   ~i~  i 选择任意多次之后背包的总价值分析。
  设dp[ i i i][ j j j]表示前   i   ~i~  i 件物品在载重为   j   ~j~  j 的背包中的最大价值,下面来分析每个dp[ i i i][ j j j]的值该如何求得。

1、二维数组
每个物品能选择任意多次,物品i选择与否的条件是什么呢?
和01背包的分析大致差不多,只是要加入在物品   i   ~i~  i 重复选择的情况下,背包总价值的计算。若物品   i   ~i~  i 可以取 { 0 , 1 , . . . , k } \{0,1,...,k\} {0,1,...,k}次,其中 k ∗ w i ≤ W k*w_i \leq W kwiW,则有
              dp[ i i i][ j j j] = max ⁡ \max max{ dp[ i − 1 i-1 i1][ j j j] , dp[ i − 1 i-1 i1][ j − k ∗ w i j-k*w_i jkwi] + k* v i v_i vi },
除了这一点和01背包有差别之外,其他的都一样,所以只需要在01背包的基础上做改动即可,即
for i i i in range(1,n+1):     #前 i i i个物品

#背包载重为   j   ~j~  j ,这里   j   ~j~  j 正序和倒序都行,因为dp是二维数组,dp[ i i i][:]的改变并不影响上一层状态dp[ i i i-1][:];
#区别01背包中的dp[ i − 1 i-1 i1][ j − w i j-w_i jwi],完全背包中的dp[ i i i][ j − w i j-w_i jwi]则是是否重复添加物品   i   ~i~  i 的语句
for j j j in range( w i w_i wi, W W W+1):

dp[ i i i][ j j j] = max ⁡ \max max{ dp[ i − 1 i-1 i1][ j j j] , dp[ i i i][ j − w i j-w_i jwi] + v i v_i vi } #dp[ i i i][ j j j] 为物品   i   ~i~  i 选择与否背包总价值较大者

  设dp[ j j j]表示载重为 j j j的背包中的物品最大价值,下面来分析每个dp[ j j j]的值该如何求得。

1、一维数组
和01背包一维的情况类似。
for i in range(1,n+1):     #前 i i i个物品

#背包载重为   j   ~j~  j ,这里   j   ~j~  j 必须正序,正序保证了对后续最优解的影响
for j in range( w i w_i wi, W W W+1):

dp[ j j j] = max ⁡ \max max{ dp[ j j j] , dp[ j − w i j-w_i jwi] + v i v_i vi } #dp[ j j j] 为物品   i   ~i~  i 选择与否背包总价值较大者

  具体的正序和逆序问题可以参考下面的文章!!!
  和01背包问题一样,完全背包也可以用一维数组来保存数据。算法样式和01背包的很相似,唯一不同的是对V遍历时变为正序,而01背包为逆序。01背包中逆序是因为F[i][]只和F[i-1][]有关,且第i件的物品加入不会对F[i-1][]状态造成影响。而完全背包则考虑的是第i种物品的出现的问题,第i种物品一旦出现它势必应该对第i种物品还没出现的各状态造成影响。也就是说,原来没有第i种物品的情况下可能有一个最优解,现在第i种物品出现了,而它的加入有可能得到更优解,所以之前的状态需要进行改变,故需要正序。
————————————————
版权声明:本文为CSDN博主「wumuzi」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wumuzi520/article/details/7014830

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值