01背包+完全背包问题

来源:互联网 发布:机械绘图软件 编辑:程序博客网 时间:2024/05/09 18:51

  背包问题已经有很多写得很好的博客,这里的背包问题只是一个个人学习总结,希望能够把问题说得更明白清楚易懂。

贴下背包九讲问题的优秀博客网址:
  http://blog.csdn.net/pi9nc/article/details/8142876

PART1:01背包问题

题目:有N件物品,第i件物品的价值为value[i],重量为weight[i],求解将哪些物品装入背包可使价值总和最大,注意每件物品只可以装一次

这里我们仍然以一个例子来看这个算法。
有一个能够承载10kg的小推车,商店中有如下物品:

序号 物品 重量(weight) 价值(value) 1 A 2 6 2 B 2 3 3 C 5 10 4 D 4 7 5 E 3 4


   那么我们现在研究一下,怎样才能让背包中物品的价值尽可能大。我们必须要有一个正确的思路,这是解题的关键。

设W[i][j]表示在背包可容纳重量j,只装序号不大于i的物品时,背包可装入物品的最大价值,value对应于各个物品的价值,weight对应于各个物品的重量。

算法DP公式:W[i][j] = max{如果装序号为i的物品,如果不装序号为i的物品}
      =max{W[i-1][j-weight[i]]+value[i] , W[i-1][j]}

算法很简单,也很容易理解,我们不难发现算法的时间复杂度为O(N*V),空间消耗就是用了个二维数组。这里可以优化的地方就是我们不使用二维数组,使用一维数组来解决这个问题。

那么我们设一维数组为array[N]
算法:我们先对A物品分析,找出只装A物品的情况的array[N];
  再添加一个B物品进行分析,我们之前已经把A物品的所有的array值都算出来了,所以可以把包含A、B物品的array[N]算出来;
  同理直至到E物品,我们就算出来了结果为array[N]。

那么难点在哪里呢?难点在于每个物品最多只能装一个。

我们对只装A物品进行分析:

序号 物品 重量(weight) 价值(value) 1 A 2 6


    <—————————–我们需要将array数组初始化为零——————————>

背包可以承载的重量 1 2 3 4 5 6 7 8 9 10 可装入的物品的最大价值array[i] 0 6 6 6 6 6 6 6 6 6


注意:我们这个表应该从10往1生成,只有这样才能保证A物品最多只装了1个,否则结果是多个,生成的错误的表如下

背包可以承载的重量 1 2 3 4 5 6 7 8 9 10 可装入的物品的最大价值array[i] 0 6 6 12 12 18 18 24 24 30

注意到这一点就没有别的什么问题了,现在贴上这道题的c语言代码:

#include <stdio.h>#include <string.h>#define N 5     //物品的件数#define W 10    //背包可容纳的最大重量#define max(a,b) (a>b?a:b)int main(){    int i,j;    int array[W+1];    int weight[] = {2,2,5,4,3},        value[] = {6,3,10,7,4};    memset(array, 0, sizeof(array));    for(i=0;i<N;i++){        for(j=W;j>=weight[i];j--){            array[j]=max(array[j],array[j-weight[i]]+value[i]);        }    }    printf("%d\n",array[W]);    return 0;}



PART2:完全背包问题

题目:有N种物品,第i件物品的价值为value[i],重量为weight[i],求解将哪些物品装入背包可使价值总和最大,注意每种物品可重复装入

如果看懂了我们上面的01背包问题,你会发现这个问题很简单,只需要我们对01背包的算法进行一丁点改变即可——就是上面说生成错误表的地方,我们就按照那种“错误”的方式生成即可得到完全背包的答案。代码该边就是在第二个循环的地方j从weight[i]到10算array数组。此处无庸赘述。

0 0
原创粉丝点击