分支限界法处理0/1背包问题

问题描述:有4个物品,其重量分别为(4,7,5,3),价值分别为(40,42,25,12),背包容量为W=13。已知每个物品不可再分割,如何选择装入背包的物品,使得装入背包中的物品的总价值最大。使用分支限界法求解该问题

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct Res {
	int weight, value;
	bool used = false;
};
struct Bags {
	vector< Res*> bags;
	int nweigt, nvalue = 0, ub;
	Bags operator+(Res*& res) {
		Bags bag = *this;
		bag.bags.push_back(res);
		bag.nweigt -= res->weight;	bag.nvalue += res->value;
		return bag;
	}
};
int main() {
	Res thing[] = { {4, 40}, { 7,42 }, { 5,25 }, { 3,12 } };
	vector<Res*> res;
	vector<Bags> result;
	for (auto& it : thing)
		res.push_back(&it);
	int W = 13;
	sort(res.begin(), res.end(), [](Res* & a, Res* & b) {return a->value / a->weight > b->value / b->weight; });		//优先排序
	Bags start;
	int up = W * res.front()->value / res.front()->weight, down = 0;
	for (int i = 0, w = W; i < res.size(); i++) {		//贪心获取下界
		if (res[i]->weight < w) {
			down += res[i]->value;
			w -= res[i]->weight;
		}
	}
	start.ub = up;	start.nweigt = W;
	int size, count = 0;
	queue<Bags> q;
	q.push(start);
	while (!q.empty()&&count<res.size()){
		size = q.size();		//记录每层的节点数,进行层处理
		for (int i = 0; i < size; i++) {
			Bags right = q.front();
			if (right.nweigt - res[count]->weight >= 0) {
				Bags left = right + res[count];		//左节点
				left.ub = left.nvalue + (count + 1 < res.size() ? left.nweigt * (res[count + 1]->value / res[count + 1]->weight) : 0);	//无法访问最后一层的count+1,值为0
				q.push(left);
			}
			right.ub = right.nvalue + (count + 1 < res.size() ? right.nweigt * (res[count + 1]->value / res[count + 1]->weight) : 0);	//修改右结点
			if (right.ub > down)	
				q.push(right);
			else
				result.push_back(right);
			q.pop();
		}
		count++;
	}
	Bags* minBag = nullptr;
	for (int i = 0; i < result.size(); i++) {	//在表中寻找最优方案
		if (minBag == nullptr || result[i].nvalue > minBag->nvalue)
			minBag = &result[i];
	}
	for (auto& it : minBag->bags)
		it->used = true;
	cout << "分支限界法求得最大价值为:" << minBag->nvalue << endl;
	for (int i = 0; i < res.size(); i++)
		cout << "物品" << i + 1 << "是否被选:" << thing[i].used << endl;
	return 0;
}

 

0/1背包问题是指:有一个容量为C的背包和n个物品,每个物品有一个重量w和一个价值v,要求在不超过背包容量的情况下,选出一些物品放入背包,使得背包中物品的总价值最大。 分支限界法是一种求解最优化问题的重要方法,它可以用于求解0/1背包问题。具体步骤如下: 1. 定义节点:将可行解空间按照某种方式分解为多个子集,每个子集对应一个节点,节点代表了一个可行解的一部分。 2. 定义限界函数:对于每个节点,定义一个限界函数,用于估计该节点的可行解空间中可能存在的最优解的上限,以便在搜索的过程中优先考虑可能存在的最优解。 3. 搜索过程:从根节点开始,按照某种方式对节点进行扩展和剪枝,直到找到最优解或无法继续扩展为止。搜索过程中需要维护一个活结点表,用于保存待扩展的节点信息。 具体到0/1背包问题分支限界法的搜索过程如下: 1. 初始化:将根节点加入活结点表中,背包的剩余容量为C,当前节点代表的可行解包含所有物品。 2. 搜索过程: 1)从活结点表中取出一个节点。 2)如果该节点代表的可行解已经是完整的,则更新最优解,并进行剪枝操作。 3)否则,对该节点进行扩展,分别生成两个子节点:一个子节点表示选择当前物品放入背包,另一个子节点表示不选择当前物品放入背包。对于两个子节点分别计算限界函数,将它们加入活结点表中。 4)重复以上步骤,直到活结点表为空或找到最优解。 3. 输出最优解。 在具体实现时,可以使用优先队列来实现活结点表,以便在搜索过程中优先处理限界函数最小的节点。同时,可以使用动态规划的思想来计算限界函数,以减少重复计算。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值