算法導論--動態規劃(0-1揹包問題)

揹包問題

小偷發現了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時,最大價值

採用自底向上求解方案,先填寫第一行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;
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章