Каталог статей
предисловие
Задача проектирования рюкзака методом ветвей и границ:
имеется n предметов с весами {w1, w2, ..., wn}, и их значения равны {v1, v2, ..., vn}, для данного рюкзака мощность Вт. Составьте план по выбору некоторых предметов из этих предметов и положите их в рюкзак.Каждый предмет либо выбран, либо не выбран.Необходимо, чтобы выбранные предметы не только можно было поместить в рюкзак, но и иметь наибольшую ценность .
Найдите все решения и лучшее решение при W=6 для 4 пунктов, показанных в таблице ниже.
1. Экспериментальные процедуры и результаты
Код эксперимента:
#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++, чтобы быть ленивым, иначе некоторые операторы могут быть исчерпаны, и если вы можете быть ленивым, вы можете быть ленивым. По моему мнению, напрямую измените его на язык C. В принципе это не сложно, но лень - это принцип хахахахаха.