您的位置:首页 > 编程语言 > C语言/C++

01背包+完全背包问题

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

贴下背包九讲问题的优秀博客网址:

  http://blog.csdn.net/pi9nc/article/details/8142876

PART1:01背包问题

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

这里我们仍然以一个例子来看这个算法。

有一个能够承载10kg的小推车,商店中有如下物品:

序号物品重量(weight)价值(value)
1A26
2B2
4000
3
3C510
4D47
5E34
   那么我们现在研究一下,怎样才能让背包中物品的价值尽可能大。我们必须要有一个正确的思路,这是解题的关键。

设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

算法:我们先对A物品分析,找出只装A物品的情况的array
;

  再添加一个B物品进行分析,我们之前已经把A物品的所有的array值都算出来了,所以可以把包含A、B物品的array
算出来;

  同理直至到E物品,我们就算出来了结果为array


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

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

序号物品重量(weight)价值(value)
1A26


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

背包可以承载的重量12345678910
可装入的物品的最大价值array[i]0666666666


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

背包可以承载的重量12345678910
可装入的物品的最大价值array[i]06612121818242430


注意到这一点就没有别的什么问题了,现在贴上这道题的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数组。此处无庸赘述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言