0-1背包问题(回溯法+递归实现)

问题描述:假设有7个物品,它们的重量和价值如下表所示。若这些物品均不能被分割,且背包容量C=150,使用回溯方法求解此背包问题

物品

A

B

C

D

E

F

G

重量

35

30

60

50

40

10

25

价值

10

40

30

50

35

40

30

 

代码如下:

#include <iostream>
#include <algorithm>

using namespace std;

int n;			//物品数量	
int c;			//背包容量 
int cw;			//当前背包重量 
int cp;			//当前背包装入物品价值 

int bestp;		//装包最大价值 
int bestw;		//最大价值时的背包重量 

struct object{
	char id;	//物品编号 
	int p;		//物品价值 
	int w;		//物品重量 
	double pw;	//单位重量价值 
	bool flag;	
}objects[100];

//上界函数 
int Bound(int i)
{
	int cleft = c - cw;		//当前背包剩余容量 
	double b = cp;			
	while(i < n && objects[i].w <= cleft)
	{
		cleft -= objects[i].w;
		b += objects[i].p;
		i++;
	}
	if(i < n)
		b += (1.0 * cleft) / objects[i].w * objects[i].p;
		return b;
}

bool cmp(struct object a, struct object b)
{
	return a.pw > b.pw;
}

void Backtrack(int i)
{
	//搜到叶子结点,更新bestp 
	if(i == n)
	{
		bestp = cp;
		bestw = cw;
		return;
	}
	//满足约束函数进入左子树 
	if(cw + objects[i].w <= c)
	{
		objects[i].flag = true;
		cw += objects[i].w;
		cp += objects[i].p;
		Backtrack(i + 1);
		cw -= objects[i].w;
		cp -= objects[i].p;
	}
	//满足限界函数进入右子树 
	if(Bound(i + 1) > bestp)
		Backtrack(i + 1);
}

int main()
{
	int sum_p = 0, sum_w = 0;
	cin >> n >> c;
	for(int i = 0; i < n; i++)
	{
		cin>>objects[i].id;
		objects[i].flag = false;
	}
	for(int i = 0; i < n; i++)
	{
		cin >> objects[i].w;
	}
	for(int i = 0; i < n; i++)
	{
		cin >> objects[i].p;
	}
	for(int i = 0; i < n; i++)
	{
		sum_p += objects[i].p;
		sum_w += objects[i].w;
		objects[i].pw = (1.0 * objects[i].p) / objects[i].w;
	}
	if(sum_w <= c)
	{
		cout << "背包能全装下" << endl;
		cout << "价值为:" << sum_p << endl;
		return 0;
	}
	sort(objects, objects + n, cmp);	//按物品单位重量价值非递减排序 
	Backtrack(0);
	cout << "装入背包的物品有:" << endl;						
	for(int i = 0; i < n; i++)
	{
		if(objects[i].flag == true)
			cout << objects[i].id << " "; 
	} 
	cout << endl; 
	cout << "物品装包最大价值为:" << endl; 
	cout << bestp << endl;
	cout << "装包价值最大时,物品重量为:" << endl;
	cout << bestw << endl;
	return 0;
}

/*
测试: 
7 150
A B C D E F G
35 30 60 50 40 10 25
10 40 30 50 35 40 30
*/

 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值