01背包問題的動態規划算法


01背包問題我最初學會的解法是回溯法,第一反應並不是用動態規划算法去解答。原因是學習動態規划算法的時候,矩陣連乘、最長公共子串等問題很容易將問題離散化成規模不同的子問題,比較好理解,而對於01背包問題則不容易想到將背包容量離散化抽象出子問題,從情感上先入為主也誤以為動態規划算法不是解決01背包問題的好方法,實際上並不是這樣的。另外,動態規划算法不對子問題進行重復計算,但是要自底向上將所有子問題都計算一遍,直到計算出最終問題的結果也就是我們要的答案,有點像爬山的感覺。

問題描述:給定n種物品和一背包,物品i的重量是wi,其價值為vi,背包的容量為C,求能裝入背包的物品的最大價值。
用m(i,j)表示為從i到n的物品裝入容量為j的背包能產生的最大價值,則能裝入背包的物品最大價值為m(1,C)。
遞歸式為:

 

上面講到,該問題是對背包的容量進行離散化,因此時間復雜度是O(nC)。

代碼如下(用的變量名可能和上面有小出入,但是是自描述的):

#include<iostream>
using namespace std;

struct CARGO{
    int weight;
    int value;
};

const int totalWeight=10;
const int totalNumber=5;
CARGO goods[totalNumber]={{2,6},{2,3},{6,5},{5,4},{4,6}};

//1.使用時下標都從1開始;2.遇到復雜結構的初始化用memset方法。
int result[totalNumber+1][totalWeight+1]={0};

int myMax(int i,int j)
{
    return i>=j?i:j;
}

void dp()
{
    int i,j;

    //動態規划表達式的初始化
    i=totalNumber;
    for(j=1;j<=totalWeight;j++)
    {
        if(goods[i-1].weight>j)//為保證邏輯完整性,這個if沒刪掉
        {
            result[i][j]=0;
        }
        else
        {
            result[i][j]=goods[i-1].value;
        }
    }

    for(i=totalNumber-1;i>0;i--)
    {
        for(j=1;j<=totalWeight;j++)
        {
            if(goods[i-1].weight>j)
            {
                result[i][j]=result[i+1][j];
            }
            else
            {
                result[i][j]=myMax(result[i+1][j],result[i+1][j-goods[i-1].weight]+goods[i-1].value);
            }
        }
    }
}

int main()
{
    dp();
    cout<<result[1][totalWeight]<<endl;

    //是否理解:完成用result[totalNumber][totalWeight]表示背包最大value的代碼(從前往后解決子問題的方法)。

    return 0;
}

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM