這個問題之前重複寫過,本篇博客主要分析調試方法
一.代碼實現
backpack.h
//物品不可分割的揹包問題, 可以用動態規劃.
//bestValue[i][j]=m 表示前i個物品放入容量爲j的揹包的最大價值
vector<int>w{2,5,4,2,3};//重量數組
vector<int>v{6,3,5,4,6};//價格數組
int Cont = 11; //揹包容量=10,讓第0列=0
int Num = w.size()+1;
vector<int>temp(Cont, 0);//bag[][]列數=W
vector<vector<int>>bestValue(Num,temp);//bag[][]列數=物品個數+1
vector<int>bestBag(Num,0); //記錄物品放入與否
int backpack()
{
//構造最優解
for (int i = 1; i <Num; i++) //循環數組[1][j]~[5][j]
{
for (int j = 1; j < Cont; j++)//循環[i][1]~[i][10]
{
if (w[i-1] > j) //如果當前容量裝不下第 i 個物品
{
bestValue[i][j] = bestValue[i - 1][j];
}
else
{
bestValue[i][j] = max(bestValue[i - 1][j], bestValue[i - 1][j - w[i-1]] + v[i-1]);
//有點蛋疼,V[]和W[]的第0位有意義,其他幾個數組都無意義
}
}
}
//構造最優策略,如[5][10]>[4][10],表示第5個物品已裝入,bestBag[5]=1
int j = Cont-1;
for (int i = Num - 1; i > 0; i--)
{
if (bestValue[i][j] > bestValue[i - 1][j])
{
bestBag[i] = 1;
j -= w[i-1]; //問題"前i個物品在容量 j 的最優策略" -> "前i-1個物品在容量 j-w[i]的最優策略"
}
}
return bestValue[Num - 1][Cont - 1];
}
void BagPrint() {
cout << "放入的物品有:\t";
for (int i = 1; i < Num; i++)
{
if (bestBag[i] == 1)
cout << i<<" ";
}
}
main()
cout << endl << "裝入揹包的最大價值爲:" << backpack();
cout << endl << "裝入的物品爲:"; BagPrint();
二.算法優化
①二維數組->一維數組
因爲
bestValue[i][j] = max(bestValue[i - 1][j], bestValue[i - 1][j - w[i-1]] + v[i-1]);
將bestValue[ i ][ j ] --> bv[ j ]時, 每個bv[ j ] 取決於上一次循環的bv[ j ] 、上一次循環的bv[ j-w[ i - 1 ]]
這兩個因變量均 ≦ bv[ j ], 因此,內循環必須是倒序
for i=1..Num
for j=W..1
bv[i] = max( bv[j] , bv[j - w[i-1]] + v[i-1] );
確保修改當前值時,該值的因變量未改變
bestValue_1() //基於bestValue()
int backpack_1()
{
//構造最優解
for (int i = 1; i < Num; i++) //循環物品1~5
{
for (int j = Cont-1; j >0; j--)//循環[10]~[1]
{
if (w[i - 1] <= j) //默認不裝, 當前容積能裝下,再考慮是否裝
{
bestValue_1[j] = max(bestValue_1[j - w[i - 1]] + v[i - 1], bestValue_1[j]);
}
}
}
return bestValue_1[Cont - 1];
}
②增加分類條件
當前容量( j )大於物品的重量( w[i-1] )時,纔有可能更新
將內部for循環和if語句合併
bestValue_2() //基於bestValue_1()
int backpack_2()
{
//構造最優解
for (int i = 1; i < Num; i++) //循環物品1~5
{
for (int j = Cont - 1; j >=w[i-1]; j--)//循環[10]~[w[i-1]]
{
bestValue_2[j] = max(bestValue_2[j - w[i - 1]] + v[i - 1], bestValue_2[j]);
}
}
return bestValue_2[Cont - 1];
}
PS:一直找不到一維數組如何求解最優路徑.
因爲最終的一維數組bv[j]:在容量爲 j 時最多能裝多重的物品
三.BUG分析及斷點調試
一.邊界問題
通過斷點調試,發現int backpack()中構造最優解時.i不能循環到最後一個位置
可知Bug是w[i-1]寫成了w[i].同理還有v[i]