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;
}