分支界限法--01背包问题

假期 2020.01.22

题目描述

仍然是 0 - 1背包问题。详细描述请见回溯算法–01背包问题


算法分析

此处采用分支界限算法,即bfs算法实现解决该问题,并且采用优先队列的存储方式。

  1. 存储结构,采用构造函数的目的是便于赋值,并且有两个重载函数,第一个是初始化数组,第二个是便于赋值。
struct Node {//每一个节点的信息,其中包括背包的相关信息
	int cp, rp;
	int rw;
	int id;
	int Choiced[Max_size];
	Node() { memset(Choiced, 0, sizeof(Choiced)); }//解向量初始为零
	Node(int _cp, int _rp, int _rw, int _id) {//构造函数,便于参数传递
		cp = _cp;
		rp = _rp;
		rw = _rw;
		id = _id;
	}
};
/*背包数据记录*/
struct Goods {
	int weight;
	int value;
}goods[Max_size];
  1. 首先将一个节点入队
	queue<Node> q;//创建队列
	q.push(Node(0, sum_value, weight, 1));//压入一个初始节点
  1. 结束条件是队列为空,而找到解的结束条件是物品计算完或者背包空间不够时,更新最优解
if (current > Count || current_node.rw == 0)//最后一个物品时或者没有剩余空间时
		{
			if (current_node.cp >= best){
				for (int i = 1; i <= Count; i++)
					Best_choice[i] = current_node.Choiced[i];
				best = current_node.cp;
			}
			continue;
		}
  1. 当满足限制条件时,即还有空间可容纳该物品时
if (current_rw >= goods[current].weight)//小于背包容量
		{
			lchild.rw = current_rw - goods[current].weight;
			lchild.cp = current_cp + goods[current].value;
			lchild = Node{ lchild.cp,current_rp,lchild.rw,current + 1 };
			for (int i = 1; i < current; i++)
				lchild.Choiced[i] = current_node.Choiced[i];
			lchild.Choiced[current] = 1;
			if (lchild.cp > best)//最优值更新
				best = lchild.cp;
			q.push(lchild);//左孩子入队
		}
  1. 后续物品不会构成最优解时
if (current_cp + current_rp >= best)//满足条件
		{
			rchild = Node{ current_cp,current_rp,current_rw,current + 1 };
			for (int i = 1; i < current; i++)
				rchild.Choiced[i] = current_node.Choiced[i];
			rchild.Choiced[current] = 0;
			q.push(rchild);//右孩子入队
		}
  1. 结束该程序,直到队列为空。

代码解析

#include<iostream>
#include<algorithm>
#include <queue>
using namespace std;
constexpr auto Max_size = 20;
int Best_choice[Max_size];//最优方案存储
int best = 0,weight = 0,Count = 0,sum_weight = 0,sum_value = 0;//最优值,最大容量,物品数量,物品总重量,物品总价值
struct Node {
	int cp, rp;
	int rw;
	int id;
	int Choiced[Max_size];
	Node() { memset(Choiced, 0, sizeof(Choiced)); }//解向量初始为零
	Node(int _cp, int _rp, int _rw, int _id) {//构造函数,便于参数传递
		cp = _cp;
		rp = _rp;
		rw = _rw;
		id = _id;
	}
};
/*背包数据记录*/
struct Goods {
	int weight;
	int value;
}goods[Max_size];
void bfs()
{
	int current = 0, current_cp = 0, current_rp = 0, current_rw = 0;
	queue<Node> q;//创建队列
	q.push(Node(0, sum_value, weight, 1));//压入一个初始节点
	while (!q.empty())//队列不为空时
	{
		Node current_node, lchild, rchild;
		current_node = q.front();//取出队头元素
		q.pop();//队头元素出队
		current = current_node.id;//物品序号
		if (current > Count || current_node.rw == 0)//最后一个物品时或者没有剩余空间时
		{
			if (current_node.cp >= best){
				for (int i = 1; i <= Count; i++)
					Best_choice[i] = current_node.Choiced[i];
				best = current_node.cp;
			}
			continue;
		}
		if (current_node.cp + current_node.rp < best)//不满足最优值时
			continue;
		current_cp = current_node.cp;
		current_rp = current_node.rp - goods[current].value;
		current_rw = current_node.rw;//剩余容量
		if (current_rw >= goods[current].weight)//小于背包容量
		{
			lchild.rw = current_rw - goods[current].weight;
			lchild.cp = current_cp + goods[current].value;
			lchild = Node{ lchild.cp,current_rp,lchild.rw,current + 1 };
			for (int i = 1; i < current; i++)
				lchild.Choiced[i] = current_node.Choiced[i];
			lchild.Choiced[current] = 1;
			if (lchild.cp > best)//最优值更新
				best = lchild.cp;
			q.push(lchild);//左孩子入队
		}
		if (current_cp + current_rp >= best)//满足条件
		{
			rchild = Node{ current_cp,current_rp,current_rw,current + 1 };
			for (int i = 1; i < current; i++)
				rchild.Choiced[i] = current_node.Choiced[i];
			rchild.Choiced[current] = 0;
			q.push(rchild);//右孩子入队
		}
	}
	return;
}
int main()
{
	cout << "请输入物品个数:";
	cin >> Count;
	cout << "请输入背包的容量:";
	cin >> weight;
	cout << "请输入各物品的重量与价值(用空格分开):" << endl;
	for (int i = 1; i <= Count; i++){
		cin >> goods[i].weight >> goods[i].value;
		sum_weight += goods[i].weight;
		sum_value += goods[i].value;
	}
	if (sum_weight <= weight) {
		best = sum_weight;
		cout << "放入的最大价值是:" << best << endl;
		cout << "选择方案是将所有物品全部装入背包即可";
	}
	else {
		bfs();
		cout << "放入的最大价值是:" << best << endl;
		cout << "选择方案是: ";
		for (int i = 1; i <= Count; i++)
			if (Best_choice[i] == 1)
				cout << i << " ";
	}
	cout << endl;
	return 0;
}

运行结果

在这里插入图片描述


参考

实现有所参考《趣学算法》

发布了166 篇原创文章 · 获赞 45 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44116998/article/details/104069909