这个问题之前重复写过,本篇博客主要分析调试方法
一.代码实现
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]