算法导论16.2-2--动态规划(0-1背包问题)

来源:互联网 发布:java单线程改多线程 编辑:程序博客网 时间:2024/06/17 05:46

转载出处:http://blog.csdn.net/luoshixian099/article/details/46572285

背包问题

小偷发现了n个商品,第i个商品重量为wi,价值为vi。小偷希望尽量拿走价值高的商品,但是他的背包只能容纳W重的商品。求如何取舍这些商品? 
由于对一个商品,要么被拿走要么不被拿走,所以被称为0-1背包问题。 
我们如果采取枚举法进行比较,将会有2n个情况,算法复杂度与n呈指数关系。 
下面分析背包问题的性质:

动态规划

最优子结构

xi=1,表示第i个商品被拿走,xi=0,表示第i个商品不被拿走。 
则问题变为求V=maxni=1xivi约束条件为ni=1xiwiW,求最大值的x1,x2,x3..xn解; 
对于第k个商品,决定是否装包,需要进行比较,如果拿装包即xk=1,求子问题V=maxni=1xivi(ik),约束条件为ni=1xiwi(xk)Wwk。如果不装包,xk=0V′′=maxni=1xivi(ik),约束条件不变ni=1xiwi(xk)W 。比较VV′′大小。

自底向上求解方案

算法复杂度为O(nW) 
令c[i][j]表示第1个商品到第i个商品中,背包容量为j的情况下,可获得的最大价值;

决定是否选择商品i的方案,比较选与不选的获得的价值 
c[i][j] = max(c[i-1][j] ,v[i]+c[i-1][j-w[i]]) 
例:

int w[]={0,3,6,3,8,6};//商品重量 第一数值为0,为了方便编程int v[]={0,4,6,6,12,10};//商品价值 第一数值为0,为了方便编程int W = 10; //背包容量int c[6][11]={0};//c[i][j]表示在商品1到i中,背包容量为j时,最大价值
  • 1
  • 2
  • 3
  • 4

采用自底向上求解方案,先填写第一行c[1][j],此时只有商品1可选,当j<w[1]时,背包容量小于商品1的大小,所以c[1][j] =0,当jw[1]时,背包内价值即为商品1的价值c[1][j] = v[1]=4; 
这里写图片描述 
填写第二行:c[2][j],此时可选商品为1和2 。当j<w[2],商品2一定装不了,但可能装下商品1,所以即c[2][j] = c[1][j],当jw[2],此时可以装下商品2,如当j=6时,如果选择商品2,那么此时背包容量为j-w[2]=0,留给商品1用,而c[1][0]=0,所以背包价值为c[2][6]=v[2]+c[1][0];如果不选商品2,则c[2][6]=c[1][6]=4,比较大小得到,应该把商品2装包。即c[2][6]=v[2]+c[1][0]=6+0=6; 
又如:当j=10时,如果选择商品2,则背包容量还剩j-w[2]=4;而c[1][4]=4,此时背包总价值为c[2][10]=v[2]+c[1][4]=6+4=10;如果不选商品2,c[2][10] =c[1][10]=4;选取最大值即c[2][10]=10; 
这里写图片描述 
按照上述方式自底向上填写表格: 
这里写图片描述

构造最优解

按照上面描述:如果c[i][j] = c[i-1][j],表明商品i没有被选择;否则就被选择 
从表格的右下端开始,即c[5][10],回溯。 
c[5][10]c[4][10]则商品5被选择,而此时背包容量j-w[5]=4;继续向上回溯,比较c[4][4]=c[3][4],表明商品4不选。回溯到第一个商品时,如果c[1][j]0,表明被装包;

完整代码

/************************************************************************CSDN 勿在浮沙筑高台 http://blog.csdn.net/luoshixian099算法导论--动态规划(0-1背包问题)2015年6月19日                    ************************************************************************/#include <iostream>using namespace std;#define max(a,b) (((a) > (b)) ? (a) : (b))int w[]={0,3,6,3,8,6};//商品重量int v[]={0,4,6,6,12,10};//商品价值int W = 10; //背包容量int c[6][11]={0};//c[i][j]表示在商品1到i中,背包容量为j时,最大价值void Package0_1(int w[],int v[],int W,int n,int c[][11])//{    for(int i=1;i<=n;i++)          //逐行填表c[i][j]    {        for (int j=1;j<=W;j++)        {            if ( i == 1)       //填写第1行时,不参考其他行            {                if (j < w[i])                    c[i][j]=0;                else                    c[i][j] = v[i];            }            else            {                if ( j < w[i])  //背包容量小于商品i的重量,商品i一定不选                {                    c[i][j] = c[i-1][j];                }                else                {                    c[i][j] = max(c[i-1][j],v[i]+c[i-1][j-w[i]]);//比较选与不选商品i的背包总价值大小                }            }        }    }    for(int m =1;m<6;m++)    {        for (int n=0;n<11;n++)        {            cout<<c[m][n]<<"  ";        }        cout<<endl;    }}void Print_Package0_1(int c[][11])  //构造解{    int i=5;    int j=10;    cout<<"总价值为"<<c[i][j]<<endl;    while(i!=1)    {        if ( c[i][j] == c[i-1][j] )        {            cout<<"商品"<<i<<"不选"<<endl;        }        else        {            cout<<"商品"<<i<<"选"<<endl;            j = j - w[i];        }        i--;    }    if ( c[i][j] == 0)   //    {        cout<<"商品"<<i<<"不选"<<endl;    }    else    {        cout<<"商品"<<i<<"选"<<endl;    }}int main(){   Package0_1(w,v,W,5,c);   Print_Package0_1(c);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

这里写图片描述

阅读全文
0 0
原创粉丝点击