基本算法-0/1背包问题

系统 1478 0

  关于0/1背包问题网上有非常多的博文,在此我谨记录一下自己的理解。

  问题表述:有N件物品和一个容量为V的背包。第i件物品的体积是C[i](0<=i<=N-1),价值是W[i]。求解将哪些物品装入背包可使价值总和最大。每个物品最多只可以放入背包一次。

  这个问题的经典解法思路如下:

  我们用f[i][j]表示在考虑前i个物品时体积为j的背包的最大价值,注意,我们并不是把前i个物品全部放入背包,而是考虑i个物品中挑选一些放入背包,使得价值最大的那些情况。

  首先,我们考虑只有1个物品(第0个)时,容量分别为0,1,...,V的各背包所包含物品的最大价值。很明显,容量大于等于C[0]的背包的最大价值为W[0],容量小于C[0]的背包的最大价值为0。

  然后,我们考虑再来一个(第i个)物品时,容量分别为0,1,...,V的各背包所包含物品的最大价值。对于某个背包,我们有两种选择:将该物品放入该背包或者不放入。

  当我们将该物品放入某个体积为j的背包时,该背包的最大价值为f[i][j-C[i]]+W[i]。当我们不把该物品放入某个体积为j的背包时,该背包的最大价值为f[i-1][j]。所以在考虑前i个物品时,体积为j的背包的最大价值为f[i][j]=max{f[i-1][j],f[i][j-C[i]]+W[i]}.

  迭代以上步骤,从i=0到N-1,最后得到的f[N-1][V]就是最后的答案。

  上述算法的时间复杂度为O(VN),空间复杂度也是O(VN)。时间复杂度是最优的,而空间复杂度可以进一步优化:我们注意到在公式f[i][j]=max{f[i-1][j],f[i][j-C[i]]+W[i]}中,对于j从0到V,f[i][j]只与f[i-1][j]有关,而与i-2,i-3等情况下的f无关,所以我们只需要考虑前一次迭代(亦即i-1)的结果就可以。亦即f[j]=max{f[j],f[j-C[i]]+W[i]}.又因为在计算f[j]时用到了比j小的f:f[j-C[i]],所以在对j进行迭代时应该从后向前迭代: 

 

      
        1
      
      
        for
      
      (
      
        int
      
       i=0;i<N;i++
      
        ){

      
      
        2
      
      
        for
      
      (
      
        int
      
       j=V;j>=0;j--
      
        ){

      
      
        3
      
      
        if
      
      (j-item[i][0]>=0){
      
        //
      
      
        此处判断是为了防止将j物品放入容量小于C[j]的背包中
      
      
        4
      
                           f[j]=max(f[j],f[j-item[i][0]]+item[i][1
      
        ]);

      
      
        5
      
      
                        }

      
      
        6
      
      
                    }           

      
      
        7
      
               }
    

  我们可以用一个例子来展示一下上述代码迭代的过程。取V=10,N=3.三个物品的体积分别为3,4,5.价值分别为4,5,6,迭代过程中f数组的值为:

  0 0 0 4 4 4 4 4 4 4 4
  0 0 0 4 5 5 5 9 9 9 9
  0 0 0 4 5 6 6 9 10 11 11

  第一行为只考虑第1个物品的情况。所有容量大于等于3的背包的价值都为该物品的价值:4.

  第二行为只考虑前2个物品的情况。所有容量大于等于7的背包可以同时容纳前2个物品,价值为4+5=9,容量为4-6的背包可以容纳第2个物品,价值为5,容量为3的背包可以容纳第1个物品,价值为4.

  第三行以此类推。

  我们取最后1行的最后一个数字为结果,亦即考虑所有3个物品的体积为10的背包的最大价值,为11.

参考文献:

  [1] 0/1问题 动态规划法

  [2] 背包问题九讲 第一讲 0/1背包问题

  [3] 背包之0/1背包 完全背包 多重背包详解

 

基本算法-0/1背包问题


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论