分支限界法法解决问题(C++语言)


前言

通过分支限界法设计背包问题:
有n个重量分别为{w1,w2,…,wn}的物品,它们的价值分别为{v1,v2,…,vn},给定一个容量为W的背包。设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中,要求选中的物品不仅能够放到背包中,而且具有最大的价值。
对下表所示的4个物品求出W=6时的所有解和最佳解。
在这里插入图片描述


一、实验步骤及结果

实验代码:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int n;
int c;//定义物品结构体
struct Item
{
    
    
	int ItemID;//物品编号
	int value;//物品价值
	int weight;//物品重量
	int ratio;
};
struct Node
{
    
    
	Node(){
    
    
		value = 0;
		weight = 0;
		level = 0;
		parent = 0;
		bound = 0;
	}
	//搜索到该节点的价值
	int value;
	//搜索到该节点的总重量
	int weight;
	//搜索以该节点子树能达到的价值上界
	int bound;
	//层次
	int level;
	//父节点
	struct Node *parent;
};
struct cmp
{
    
    
	bool operator()(Node *a, Node *b){
    
    
		return a->bound < b->bound;
	}
};


bool Itemcmp(Item item1, Item item2);//比较函数
int branchAndBound(Item items[], int c);//分支限界法
int searchCount = 0;
int maxSize = 0;
float maxBound(Node *node, Item items[], int c);//限界函数

int main(){
    
    
	int maxValue;
	cout << "请输入物品的个数:";
	cin >> n;
	cout << "请输入背包容量:";
	cin >> c;
	int *w = new int[n];
	int *v = new int[n];
	cout << "请输入" << n << "个物品的质量:" << endl;
	for (int i = 0; i < n; i++)
	{
    
    
		cin >> w[i];
	}
	cout << "请输入" << n << "个物品的价值:" << endl;
	for (int i = 0; i < n; i++)
	{
    
    
		cin >> v[i];
	}

	//定义物品结构体
	Item *items = new Item[n];
	//初始化结构体数组
	for (int i = 0; i < n; i++)
	{
    
    
		items[i].ItemID = i;
		items[i].value = v[i];
		items[i].weight = w[i];
		items[i].ratio = 1.0*v[i] / w[i];
	}
	//按价值率排序
	sort(items, items + n, Itemcmp);
	cout << "商品的价值依次为:";
	for (int i = 0; i < n; i++)
	{
    
       
		cout << v[i] << "  ";
	}
	cout << endl;
	cout << "商品的质量分别为:";
	for (int i = 0; i < n; i++)
	{
    
    
		cout << w[i] << " ";
	}
	cout << endl;
	cout << "选取方案为:" << endl;
	maxValue = branchAndBound(items, c);
	cout << "最大价值为:" << maxValue;
	getchar();
	getchar();
	getchar();
	delete []w;
	delete []v;
}

//比较函数
bool Itemcmp(Item item1, Item item2){
    
    
	return item1.ratio > item2.ratio;
}

//分支限界函数
int branchAndBound(Item items[], int c){
    
    
	int *x = new int[n];
	for (int i = 0; i < n; i++)
	{
    
    
		x[i] = 0;
	}
	//保存最大价值
	int maxValue;
	//保存当前最大价值节点
	Node *maxNode = new Node();
	//最大价值优先队列
	priority_queue<Node *, vector<Node *>, cmp> maxQueue;
	Node *firstNode, *curNode;
	
	searchCount = 1;
	firstNode = new Node();
	firstNode->bound = maxBound(firstNode, items, c);
	firstNode->parent = NULL;
	maxQueue.push(firstNode);
	maxValue = 0;
	maxNode = firstNode;
	while (!maxQueue.empty()){
    
    
		curNode = maxQueue.top();
		maxQueue.pop();
		//扩展左孩子节点
		if (curNode->weight + items[curNode->level].weight <= c){
    
    
			Node *leftNode = new Node();
			leftNode->value = curNode->value + items[curNode->level].value;
			leftNode->weight = curNode->weight + items[curNode->level].weight;
			leftNode->level = curNode->level + 1;
			leftNode->parent = curNode;
			leftNode->bound = curNode->bound;
			if (leftNode->level<n)
			{
    
    
				maxQueue.push(leftNode);
				searchCount++;
			}
			if (maxValue<leftNode->value)
			{
    
    
				maxValue = leftNode->value;
				maxNode = leftNode;
			}
		}

		//扩展右孩子节点
		if (maxBound(curNode, items, c)>maxValue){
    
    
			Node *rightNode = new Node();
			rightNode->value = curNode->value;
			rightNode->weight = curNode->weight;
			rightNode->level = curNode->level + 1;
			rightNode->parent = curNode;
			rightNode->bound = maxBound(rightNode, items, c);
			if (rightNode->level<n)
			{
    
    
				maxQueue.push(rightNode);
				searchCount++;
			}
		}
		if (maxQueue.size()>maxSize)
		{
    
    
			maxSize = maxQueue.size();
		}
	}
	curNode = maxNode;
	while (curNode)
	{
    
    
		int tempValue = curNode->value;
		curNode = curNode->parent;
		if (curNode&&curNode->value != tempValue){
    
    
			x[items[curNode->level].ItemID] = 1;
		}
	}
	for (int i = 0; i < n; i++)
	{
    
    
		cout << x[i] << "  ";
	}
	cout << endl;
	return maxValue;
}

//限界函数
float maxBound(Node *node, Item items[], int c){
    
    
	float maxValue;
	//背包剩余容量
	int restCapacity;
	int i;

	maxValue = node->value;
	restCapacity = c - node->weight;
	i = node->level;

	while (i<n&&restCapacity>items[i].weight)
	{
    
    
		maxValue += items[i].value;
		restCapacity -= items[i].weight;
		i++;
	}
	if (restCapacity!=0)
	{
    
    
		maxValue += restCapacity*items[i].ratio;
	}
	return maxValue;
}

运行结果:
在这里插入图片描述
这里偷懒了0表示不被选择,1表示选择,如果不习惯可以加一个判断语句0输出不选择,1表示选择,这样就能方便处理了。

总结

上界函数很重要刚开始上界函数设置的并不好,导致搜索范围过大,整个算法不好,首先要在广度进行遍历,选择活结点,同时思路为先进先出,emmm还用到了结构体所以用到了c++偷懒,否则有些语句可能会累死,能偷懒就偷懒,emmm可以直接根据我这个改成C语言基本没啥难度,但是偷懒这是原则哈哈哈哈哈。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_51759592/article/details/125864446
今日推荐