回溯——0-1背包问题

1、算法描述
   0-1背包问题时子集选取问题。0-1背包问题的解空间可用子集树表示。集0-1背包问题的回溯法与装载问题的回溯法十分相似。在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树中可能包含最优解时才进入右子树搜索。否则将右子树剪去。设r是当前剩余物品价值总和;cp是当前价值,bestp是当前最优价值。当cp+r<<bestp时,可剪去右子树。计算右子树中解的上界的更好方法是将剩余物品依其单位价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。由此得到的价值是右子树中解的上界。
 
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;

template <class Typew,class Typep>
class Knap {
public :
	Typep Bound(int i);
	void Backtrack(int i);
	Typew c;		//背包容量
	int n;			//物品数
	int *bestx;		//记录当前最优装载
	Typew *w;		//物品重量数组
	Typep *p;		//物品价值数组
	Typep cp;		//当前价值
	Typew cw;		//当前重量
	Typep bestp;	//当前最优价值
};

template<class Typew,class Typep>
void Knap<Typew,Typep>::Backtrack(int i)
{
	if(i>n) {//达到叶子节点
		bestp=cp;
		for(int j=1;j<=n;j++)
			printf("%d ",bestx[j]);
		printf("\n");
		return ;
	}
	if(cw+w[i]<=c) //进入左子树
	{	
		bestx[i]=1;
		cw+=w[i];
		cp+=p[i];
		Backtrack(i+1);
		cw-=w[i];
		cp-=p[i];
	}
	if(Bound(i+1)>bestp)//进入右子树
	{
		Backtrack(i+1);
		bestx[i]=0;
	}
}

template<class Typew,class Typep>
Typep Knap<Typew,Typep>::Bound(int i)
{
	Typew cleft = c-cw;//剩余容量
	Typep b = cp;
	//以物品单位重量价值递减序装入物品
	while(i<=n&&w[i]<=cleft)
	{
		cleft-=w[i];
		b+=p[i];
		i++;
	}
	//装满背包
	if(i<=n)
		b+=p[i]*cleft/w[i];
	return b;
}

class Object{
	friend int Knapspack(int *,int *,int ,int);
public :
	int operator<=(Object a)const
	{
		return (d>=a.d);
	}
public:
	int ID;
	float d;
};

bool cmp(Object A,Object B)
{
	if(B.d<=A.d)
		return true;
	else
		return false;
}

template<class Typew,class Typep>
Typep Knapstack(Typep p[],Typew w[],Typew c,int n)
{
	//为Knap::Backtrack初始化
	Typew W=0;
	Typep P=0;
	Object * Q = new Object[n];
	for(int i=1;i<=n;i++)
	{
		Q[i-1].ID=i;
		Q[i-1].d=1.0*p[i]/w[i];
		P+=p[i];
		W+=w[i];
	}
	if(W<=c)
		return P;//装入所有物品
	//依物品单位重量价值排序
	sort(Q,Q+n,cmp);
//	for(int j=1;j<=n;j++)
//		printf("%f ",Q[j-1].d);
	Knap<Typew,Typep> K;
	K.bestx = new int[n+1];
	for(int j=0;j<=n;j++)
		K.bestx[j]=0;
	K.p = new Typep[n+1];
	K.w = new Typew[n+1];
	for(int i=1;i<=n;i++)
	{
		K.p[i]=p[Q[i-1].ID];
		K.w[i]=w[Q[i-1].ID];
	}
	K.cp = 0;
	K.cw = 0;
	K.c = c;
	K.n = n;
	K.bestp = 0;
	//回溯搜索
	K.Backtrack(1);
	delete[] Q;
	delete[] K.w;
	delete[] K.p;
	return K.bestp;
}

void main()
{
	int p[]={0,9,10,7,4};
	int w[]={0,3,5,2,1};
	int n=4;
	int c=7;
	int sum;
	sum=Knapstack(p,w,c,n);
	printf("%d \n",sum);
	system("pause");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值