递归(深度搜索)实现0/1背包问题

  • Post author:
  • Post category:其他



问题描述:

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?


思路:(深度搜索)

从第一个物品开始放进背包,如果能放下,继续放下一个物品,如果放不下,忽略本物品,放下一个物品。

思路很简单,下面是用递归实现的代码:下面给了两个例子来验证结果

#include <iostream>

using namespace std;
const int n = 5;    //假设5个物品
int weight[5];       //存放5个物品的重量
int value[5];        //存放5个物品的价值
int select[5];        //表示每个物品是否放入,0代表没有放入,1代表放入背包
int temp_select[5];    //临时数组,跟踪使价值最大时的放入方案

int WEIGHT = 10;
//int WEIGHT = 8;		//例1
int temp_value = 0;

void dfs(int k, int t_v, int t_w)		//从第k件物品开始搜索
{
	if (k == n) return;		//出口,当k物品已经超过最后一件时,退出
	for (int i = k; i < n; ++i)	//从第k件物品开始向后搜索
	{
		if (t_w + weight[i] <= WEIGHT)	//如果加上第i件物品可以装下
		{
			select[i] = 1;		//第i件物品选中,为t_v -= value[k] t_w -= weight[k]提供分辨
			t_w += weight[i];	//得到现在的重量
			t_v += value[i];	//得到现在的价值
			if (t_v>temp_value)	//如果比原来纪录最大的价值还大
			{
				for (int j = 0; j < 5; ++j){
					temp_select[j] = select[j];//把选中哪个的方案拷贝进临时数组中
				}
				temp_value = t_v;
			}
			dfs(i + 1, t_v, t_w);     //继续从下一件物品开始搜索
		}
		else  dfs(i + 1, t_v, t_w);	//如果第i件装不下	//就装第i+1件

		//第i个物品后面所有的装包方案已经遍历完成
		if (select[i] == 1)	//如果k个装进去了,需要拿出来,下面价值和重量都做减法
		{
			select[i] = 0;	//此时,该退出第k个,即第k个装包所有情况遍历完成
			t_v -= value[i];
			t_w -= weight[i];
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	//例1
	/*weight[0] = 5;
	weight[1] = 2;
	weight[2] = 1;
	weight[3] = 1;
	weight[4] = 6;

	value[0] = 40;
	value[1] = 12;
	value[2] = 7;
	value[3] = 8;
	value[4] = 48;*/	

	weight[0] = 2;
	weight[1] = 2;
	weight[2] = 6;
	weight[3] = 5;
	weight[4] = 4;

	value[0] = 6;
	value[1] = 3;
	value[2] = 5;
	value[3] = 4;
	value[4] = 6;
	dfs(0, 0, 0);	//给一个入口遍历
	for (int i = 0; i < 5; i++)
		cout << temp_select[i] << endl;
	cout << temp_value << endl;

	return 0;
}


结果:

上述思路很简单,理解较为简单,难在

if (select[i] == 1)    //如果k个装进去了,需要拿出来,下面价值和重量都做减法

{


select[i] = 0;    //此时,该退出第k个,即第k个装包所有情况遍历完成

t_v -= value[i];

t_w -= weight[i];

}   这一步应该放在哪个位置。第i个物品的循环,结束后应该是第i+1件物品进行递归循环,如果第i件物品是建立在放进背包的基础上的,那么需要置选择状态为0,总价值和总重量减去第i件物品的重量和价值。如果第i件物品没有放进背包,即select[i] == 0,那么不影响,直接进行i+1件物品的循环。





注:第i件物品的递归,一定会遍历完第i+1到第n件物品的所有状态





版权声明:本文为weixin_41857869原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。