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

#include<iostream>
#include<algorithm> 
#include<queue>
#include<vector>
#include<string>

using namespace std;

const int N=100;
int w[N];//记录物品重量 
int v[N];//记录物品价值 
int W;//背包最大容量 
int n;//物品个数 
int bestv;//当前记录最优价值 
int aa[N];//存放真正的最佳选择(未排序前) 
string bestx; //最优价值的选择 (排序后) 

//借助 VW结构体 辅助按照性价比放入最大堆 
struct VW{
	int value;
	int weight;
	double cp;//性价比 
	int num;//记录原来位置 
};
struct VW vw[N];
//根据性价比排序 
bool cmpvw(struct VW &x,struct VW &y){
	return x.cp>y.cp;
} 

//建立解空间树的节点 
struct node{
	int cv;//当前所装入物品的价值 
	int cw;//当前所装入物品的重量 
	int count;//当前到达第几个物品
	double maybe;//预计最大价值 
	string choose;//记录选择路线(排好序的) 
};

将vw放入优先队列不合适
//我们在取数据时并不能保证时按照最佳性价比的排序去数据 
//struct cmpvw{
//	bool operator()(struct VW &x,struct VW &y){
//		return x.cp < y.cp;//"<"从大到小排  ">"从小到大排 
//	} 
//}; 
//priority_queue<VW,vector<VW>,cmpvw> qvw;

//最大堆 
struct cmp{
	bool operator()(struct node &x,struct node &y){
		return x.maybe<y.maybe;
	}
};

//通过该函数获得可能的最大值 
double getmaybe(struct node x){
	int xw=W-x.cw;
	double may=x.cv;
	for(int i=x.count+1;i<=n;i++){
		if(xw>=vw[i].weight){
			may=may+vw[i].value;
			xw=xw-vw[i].weight;
		}
		else{
			may=may+xw*vw[i].cp;
			break;
		}
	}
	return may;
}

int main(){
	cin>>n>>W;//输入物品个数,背包最大承重 
	
	//依次输入物品的重量与价值 
	for(int i=1;i<=n;i++){
		cin>>w[i];
	} 
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	
	//将物品的价值与重量放入vw结构体数组 
	for(int i=1;i<=n;i++){
		vw[i].value=v[i];
		vw[i].weight=w[i];
		vw[i].cp=1.0*vw[i].value/vw[i].weight;
		vw[i].num=i; 
	}
	
	//按照性价比排序
	sort(vw+1,vw+n+1,cmpvw);
	
	//检查
//	for(int i=1;i<=n;i++){
//		cout<<vw[i].value<<" "<<vw[i].weight<<endl;
//	} 
	/*
	测试样例
	 
	5 15 
	1 2 3 4 5
	5 16 21 4 50
	5 8 7 1 10

	
	5 10
	2 2 6 5 4
	6 3 5 4 6
	*/
	
	priority_queue<node,vector<node>,cmp> q;

//将vw放入优先队列不合适	
//	//将vw结构体数组放入qvw堆中 
//	for(int i=1;i<=n;i++){
//		qvw.push(vw[i]);
//	}
//	
//	//检查一下 qvw最大堆 
//	while(!qvw.empty()){
//		struct VW x=qvw.top();
//		cout<<x.value<<" "<<x.weight<<endl;
//		qvw.pop();
//	}
	
	//准备工作完成,进行求解
	bestv=0;
	node a;
	a.count=0;a.cv=0;a.cw=0;a.maybe=getmaybe(a);a.choose=" ";
//	cout<<a.maybe<<endl;
	q.push(a);node x;
	while(!q.empty()){
		x=q.top();q.pop();
		if(x.cv>=bestv){
			bestv=x.cv;
	//		cout<<x.choose<<endl;
			bestx=x.choose;
		}
		if(x.maybe<bestv)continue;
		//当count层数小于n时,扩展节点 
		if(x.count<n){
			//左节点 选择 
			node l;
			l.count=x.count+1;
			l.cv=x.cv+vw[l.count].value;
			l.cw=x.cw+vw[l.count].weight;
			l.maybe=getmaybe(l);
			l.choose=x.choose+"1";
			//只有maybe大于当前最大时,才能放入队列 
			if(l.maybe>=bestv&&l.cw<=W) q.push(l);
			//右节点 不选 
			node r;
			r.count=x.count+1;
			r.cv=x.cv;
			r.cw=x.cw;
			r.maybe=getmaybe(r);
			r.choose=x.choose+"0";
			//只有maybe大于当前最大时,才能放入队列 
			if(r.maybe>=bestv&&r.cw<=W) q.push(r);
		}
		
	}
	cout<<bestv<<endl;
	
	//获取最佳选择 
	//cout<<bestx<<endl;
	for(int i=1;i<=n;i++){
		if(bestx[i]=='1'){
			aa[vw[i].num]=1;
		}
		
	} 
	//输出最佳选择 
	for(int i=1;i<=n;i++){
		cout<<aa[i]<<" ";
	}
	cout<<endl;
	
	
} 
//BFS模板
//void bfs(int s){
//	queue<int >q;
//	q.push();
//	while(!q.empty()){
//		q.top();
//		.....
//		x.push();
//	}
//} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值