算法分析 | 動態規劃 | 01揹包問題

這個問題之前重複寫過,本篇博客主要分析調試方法

一.代碼實現

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]

 

 

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