算法分析 | 动态规划 | 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]

 

 

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