Branch and bound method to solve problems (C++ language)


foreword

Design the knapsack problem by the branch and bound method:
There are n items with weights {w1, w2, ..., wn}, and their values ​​are {v1, v2, ..., vn}, given a knapsack with a capacity of W. Design a plan to select some items from these items and put them into the backpack. Each item is either selected or not selected. It is required that the selected items not only be able to be placed in the backpack, but also have the greatest value.
Find all solutions and the best solution when W=6 for the 4 items shown in the table below.
insert image description here


1. Experimental procedures and results

Experiment code:

#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;
}

Running result:
insert image description here
I am lazy here. 0 means not selected, 1 means selected. If you are not used to it, you can add a judgment statement.

Summarize

The upper bound function is very important. At the beginning, the upper bound function was not set well, which caused the search range to be too large, and the whole algorithm was not good. First, it needs to traverse in the breadth, select live nodes, and at the same time, the idea is first in first out, emmm also uses the structure The body uses c++ to be lazy, otherwise some statements may be exhausted, and if you can be lazy, you can be lazy. Emmm can directly change it to C language according to me. It is basically not difficult, but laziness is the principle hahahahaha.
insert image description here

Guess you like

Origin blog.csdn.net/weixin_51759592/article/details/125864446