0-1背包问题

来源:互联网 发布:应用宝软件 编辑:程序博客网 时间:2024/05/18 01:08

问题描述:有N个物品和一个最大可以承受重量为c的背包。每个物品的重量为{W1,W2,W3,.....,Wn};

每个物品的价值为{p1,p2,....pn}。现求将哪些物品放入背包中可以获得最大的价值。


思路:

假设总共有n个产品,每个物品的重量为m[i] (0=<i<=n);

每个物品的价值为p[n] (0=<i<=n);

m(i,j)表示选择了第i个产品时的价值,j表示背包剩余可以承受的最大重量。


如果要求解背包中放入哪些产品可以获得最大的价值,

我们将这个问题看成n步操作,每步操作代表我们是否将第i(0=<i<=n)个产品放入背包中。

用f(i, j)表示选择第i个物品时可以获取的最大价值,j表示对应的背包剩余可以承受的最大重量。

f(i+1, j)表示选择第i+1个物品时的最大可以获取的价值。

f(i,j)步操作时,要么选择第i个产品,要么不选择第i个产品

当选取了这个产品时,则其价值为f(i+1)+p[i],则背包剩余可以容纳的重量为j-w[i];

如果没有选取这个产品,则其价值和f(i+1)相同,背包剩余可以容纳的重量不变,仍为j。

当然,如果第i个产品的重量大于背包剩余可以承受的最大重量时,

则肯定不能选取这个产品。


总结来说,即得到下面的公式:

if(w[i]  > j)//当w[i]大于背包可以容纳的重量时,则必定不选取第i个产品。

f(i, j) = f(i+1 , j);

else //否则,f(i,j)为选取和不选取两种情况下的较大值。

f(i, j) = max( f(i+1, j-w[i]) + p[i],  f(i+1, j))


这使用递归的思想很好解决,

代码如下:

#include <stdio.h>#define NUM 6#define MAX(a,b) (a)>(b)?(a):(b)int w[NUM] = {15,17,20,12,9,14};int p[NUM] = {32,37,46,26,21,30};int c = 60;//背包最大的容量。//id代表第i个元素,left表示背包剩余可以承受的重量。int pack(int id, int left){if(id >= NUM)return 0;if(w[id] > left){return pack(id+1, left);}else{return MAX(pack(id+1, left-w[id])+p[id], pack(id+1, left));}}void main(int argc, char **argv){int max = pack(0, c);printf("max=%d\n",max);}


若使用非递归的方法来解决这个问题,则需要开辟一个空间来记住选择完第i个背包时的最大价值。

具体思路:

开辟一个n*(c+1)的二维数组m。m[i][j]表示选择已经选择了{0,1,2,..,i-1,i}个物品,背包的容量为j时,

背包中物品的最大的价值数目。

二维数组的行数为物品的数目,列数为背包最大可以承受的容量+1。

接下来我们用迭代来解决这个问题:

当放入第i个物品的时候,对于背包的每个容量j(0 =< j <= c)而言,其可以装入物品的最大价值为:

如果w[i] > j, 则表示第i个物品的重量大于背包的重量,则m[i][j]为上一步选取时,背包中物品的最大价值m[i-1][j]。

如果w[i] < j, 则w[i]等于m[i-1][j-w[i]] + p[i] 和m[i-1][j]中较大的一个。


所以非递归的代码如下:

#include <stdio.h>#include <stdlib.h>#define NUM 6//0-1背包问题。void main(int argc, char **argv){int w[NUM] = {15,17,20,12,9,14};//重量int p[NUM] = {32,37,46,26,21,30};//效益int c = 60;int i, j;int m[NUM][61];//初始化。memset(m , 0, sizeof(int)*NUM*c);for(i = 0; i < NUM; i++){//对于每个物品,测试它可以放置的最大的重量。for(j = 0; j <= c; j++){if(j < w[i]){if(i >= 1)m[i][j] = m[i-1][j];}else{if(i >= 1)<span style="white-space:pre"></span>m[i][j] = (m[i-1][j]>(m[i-1][j-w[i]]+p[i]))?(m[i-1][j]):(m[i-1][j-w[i]]+p[i]);else m[i][j] = p[i];}}}printf("max=%d\n",m[NUM-1][c]);//最大的元素放置在m[NUM-1][c]位置上。}









0 0
原创粉丝点击