0-1背包(分支限界法)

分支限界法:

      分支限界法(branch and bound method)是求解纯整数规划或混合整数规划问题的经典方法,在上世纪六十年代由Land Doig和Dakin等人提出。这种方法灵活且便于用计算机求解,目前已经成功运用于求解生产进度问题、旅行推销员问题、工厂选址问题、背包问题及分配问题等。算法基本思想如下:

  1. 以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树
  2. 分支限界法中,每一个活结点只有一次机会成为扩展结点,活结点一旦成为扩展结点,就一次性产生其所有儿子结点,其中导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中
  3. 然后从活结点表中取下一结点成为当前扩展结点
  4. 重复上述结点扩展过程,直至到找到所需的解或活结点表为空时为止

问题表述:

      假定n个商品重量分别为w0, w1, ..., wn-1,价值分别为p0, p1, ..., pn-1,背包载重量为C。怎样选择商品组合,使得价值最高?

队列式分支限界法

      按照队列先进先出(FIFO)原则选取下一个结点为扩展结点,从活结点表中取出结点的顺序与加入结点的顺序相同,因此活结点表的性质与队列相同

#include 
#include  

using namespace std;
int maxV = -99999,maxCount = -1;

int main(void)
{
	int num = 0,bag = 0;
	int *feet[3],count = 0; 
	int *weight,*value;
	queue<int> things,values,bags;  //广度遍历时保存状态 
	
	cout<<"请输入背包的容量"<<endl;
	cin>>bag;
	cout<<"请输入物品的数目"<<endl;
	cin>>num;
	num++;
	
	weight = (int *)malloc(sizeof(int)*num);
	value = (int *)malloc(sizeof(int)*num);
	
	feet[0] = (int *)malloc(sizeof(int)*num);
	feet[1] = (int *)malloc(sizeof(int)*num);
	feet[2] = (int *)malloc(sizeof(int)*num);
	
	cout<<"请输入物品的属性:重量和价值"<<endl;
	for(int i=1;i<num;i++)
	{
		cin>>weight[i]>>value[i];
	}
	for(int i=1;i<num;i++)
	{
		things.push(i);
		values.push(0);
		bags.push(bag);
		
		while(!things.empty())
		{
			int curNum = things.front();
			int curValue = values.front();
			int curBag = bags.front();
			
			curBag -= weight[curNum];
			curValue += value[curNum];
			//记录足迹 
			feet[0][count] = curNum;
			feet[1][count] = values.front();
			feet[2][count++] = curValue;
			
			things.pop();
			values.pop();
			bags.pop();
			//子节点满足条件的依次加入队列 
			for(int j = curNum+1;j<num;j++)
			{
				if(curBag-weight[j]>=0) 
				{
					things.push(j);
					values.push(curValue);
					bags.push(curBag);
				}
			}
			if(curValue>maxV)
			{
				maxV = curValue;
				maxCount = count-1;
			}
		}
	}
	cout<<"最大价值为:"<<maxV<<endl;
	int valueS = feet[1][maxCount];
	cout<<"最优解个数为:"<<feet[0][maxCount]<<" ";
	for(int i = maxCount;i>=0;i--)
	{
		if(valueS==feet[2][i])
		{
			cout<<feet[0][i]<<" ";
			valueS = feet[1][i];
		}
	}
	cout<<endl;
	return 0;
} 

优先队列式分支限界法(代价最小或效益最大):

      每个结点都有一个对应的耗费或收益,以此决定结点的优先级,从优先队列中选取优先级最高的结点成为当前扩展结点,如果查找一个具有最小耗费的解:则活结点表可用小顶堆来建立,下一个扩展结点就是具有最小耗费的活结点 ,如果希望搜索一个具有最大收益的解:则可用大顶堆来构造活结点表,下一个扩展结点是具有最大收益的活结点。

0-1背包(分支限界法)_第1张图片
#include 
#include 
using namespace std;
typedef struct node
{
	int maxValue;
	int bag;
	int deep;
	int route[20];   //记录路径 
}node; 
int search(int *weight,int *value,int bag,int num);
node maxNode;
int main(void)
{
	int num = 0,bag = 0;
	int *weight,*value;
	cout<<"请输入背包的容量"<<endl;
	cin>>bag;
	cout<<"请输入物品的数目"<<endl;
	cin>>num;
	num++;
	weight = (int *)malloc(sizeof(int)*num);
	value = (int *)malloc(sizeof(int)*num);
	cout<<"请输入物品的属性:重量和价值"<<endl;
	for(int i=1;i<num;i++)
	{
		cin>>weight[i]>>value[i];
	}
	cout<<search(weight,value,bag,num)<<endl;
	for(int i=0;i<num-1;i++)
	{
		cout<<maxNode.route[i]<<" ";
	}
	cout<<endl;
	return 0;
} 
int search(int *weight,int *value,int bag,int num)
{
	int max = -1;
	stack<node> list;
	node start;
	start.maxValue = 0;
	start.bag = bag;
	start.deep = 0;
	list.push(start);
	while(!list.empty())
	{
		node curNode = list.top();
		list.pop();
		int curBag = curNode.bag;
		int curDeep = curNode.deep;
		int curMaxValue = curNode.maxValue;
		
		if(curDeep>=num-1) continue;
		
		node nodeTmpLeft,nodeTmpRight = curNode;
		nodeTmpRight.deep = curDeep + 1;
		for(int i=0;i<=curDeep;i++)
		{
			nodeTmpLeft.route[i] = curNode.route[i];
			nodeTmpRight.route[i] = curNode.route[i];
		}
		
		nodeTmpRight.route[curDeep] = 0;
		
		
		if(curBag>=weight[curDeep+1])
		{
			nodeTmpLeft.maxValue = curMaxValue + value[curDeep+1];
			nodeTmpLeft.deep = curDeep + 1;
			nodeTmpLeft.bag = curBag - weight[curDeep+1];
			nodeTmpLeft.route[curDeep] = 1;
			if(max<nodeTmpLeft.maxValue)
			{
				max = nodeTmpLeft.maxValue;
				maxNode = nodeTmpLeft;
			}
			if(nodeTmpLeft.maxValue>curMaxValue)
			{
				list.push(nodeTmpRight);
				list.push(nodeTmpLeft);
			}else
			{
				list.push(nodeTmpLeft);
				list.push(nodeTmpRight);
			}
		}else
		{
			list.push(nodeTmpRight);
		}
	}
	return max;
}

你可能感兴趣的:(朝花夕拾,01背包,数据结构,算法,分支限界,队列)