分枝限界法求0-1背包问题

实例:假设有4个物品,其重量分别为(4, 7, 5, 3),价值分别为(40, 42, 25, 12),背包容量W=10。将给定物品按单位重量价值从大到小排序,结果如下:

物品 重量                                       w                                    w                       w 价值                                       v                                    v                       v 单位重量的价值                                                  w                                v                                              \frac{w}{v}                       vw
1 4 40 10
2 7 42 6
3 5 25 5
4 3 12 4

思路:
分枝限界法求0-1背包问题

分枝限界法求0-1背包问题

分枝限界法求0-1背包问题
代码实现:

/***************************///编译软件:vs&dev//程序可能不够完善,抛砖引玉/***************************/#include<iostream>#include<queue>using namespace std;#define NUM_GOODS 4 //商品数量#define  CAPACITY 10 //背包大小//商品信息typedef struct Goods{int id;//商品编号int weight;//商品重量int value;//商品价值int unit_value;//单位重量商品价值} Goods;//结点信息typedef struct Node{int depth;//结点深度int weight;//当前节点重量int value;//当前节点价值int ub;//当前节点估算上界int flag;//当前节点是左孩子还是右孩子,1:左;0:右,-1:根节点Node *parent;//指向父节点指针} Node;//最大优先队列比较方式struct cmp{bool operator()(Node *a, Node *b){return a->ub < b->ub;}};//全局变量Goods goods[NUM_GOODS + 1];//定义商品表const int capacity = CAPACITY; //定义背包大小int down;//下界int up;//上界Node *maxValue;//最优节点//功能:初始化商品信息表void initGoods(){int w[] = {4, 7, 5, 3};int v[] = {40, 42, 25, 12};for (int i = 0; i < NUM_GOODS + 1; i++){goods[i + 1].id = i + 1;goods[i + 1].weight = w[i];goods[i + 1].value = v[i];goods[i + 1].unit_value = float(goods[i + 1].value) / float(goods[i + 1].weight);}}//功能:获取当前根节点最大价值估值int getBound(Node *node){int ub;//估计该节点最大价值int remain = capacity - node->weight;//背包剩余容量if (node->depth < NUM_GOODS)//非叶节点{if (node->flag)//如果是左孩子,东西放入ub = node->value + remain * goods[node->depth + 1].unit_value;//上界=已有价值+(背包容量-已装入重量)*单价最大物品else//右孩子结点,东西不放入ub = node->value + remain * goods[node->depth + 1].unit_value;}else//为叶节点{ub = node->value;//没有东西再加入if (ub > down)//更新下界down = ub;maxValue = node;//为目前最优节点}if (node->flag)cout << "商品“" << node->depth << "”放入背包;w=" << node->weight << ";v=" << node->value << ";ub=" << ub << endl;elsecout << "商品“" << node->depth << "”不放入背包;w=" << node->weight << ";v=" << node->value << ";ub=" << ub << endl;return ub;}//功能:分支限界算法void branchAndBound(){down = goods[1].value;//最小价值,只放最贵物品,解向量(1,0,0,0)up = goods[1].unit_value * capacity;//最大价值,最贵物品单价*背包重量Node *root = new Node();//根节点root->depth = 0;root->weight = 0;root->value = 0;root->flag = -1;root->ub = up;maxValue = root;//用根节点初始化最大值节点指针,避免while循环中的判断出错priority_queue<Node *, vector<Node *>, cmp> pt;//最大优先队列pt.push(root);//根节点入队while (!pt.empty()){Node *currentNode, *leftChild, *rightChild;currentNode = pt.top();//取队首元素pt.pop();//出队//左孩子leftChild = new Node();leftChild->depth = currentNode->depth + 1;leftChild->weight = currentNode->weight + goods[leftChild->depth].weight;if (leftChild->weight < capacity){leftChild->value = currentNode->value + goods[leftChild->depth].value;leftChild->flag = 1;leftChild->parent = currentNode;//指向父节点的指针leftChild->ub = getBound(leftChild);if (leftChild->ub >= down)//剪去最大估计值比边界还小的支{if (leftChild->depth == NUM_GOODS)//已找到最大价值break;pt.push(leftChild);}}else//不满足重量约束条件cout << "商品“" << leftChild->depth << "”加入背包;w=" << leftChild->weight << " 大于 背包容量=" << capacity << ",无效解" << endl;//右孩子rightChild = new Node();rightChild->depth = currentNode->depth + 1;rightChild->weight = currentNode->weight;if (rightChild->weight < capacity){rightChild->value = currentNode->value;rightChild->flag = 0;rightChild->parent = currentNode;//指向父节点的指针rightChild->ub = getBound(rightChild);if (rightChild->ub >= down)//剪去最大估计值比边界还小的支{if (rightChild->depth == NUM_GOODS)//已找到最大价值break;pt.push(rightChild);}}else//不满足重量约束cout << "商品“" << rightChild->depth << "”加入背包;w=" << rightChild->weight << " 大于 背包容量=" << capacity << ",无效解" << endl;if (maxValue->depth == NUM_GOODS)//已找到最大价值break;}}//功能:输出结果void printResult(){int x[NUM_GOODS];//解向量Node *p = maxValue;for (int i = NUM_GOODS - 1; i >= 0; i--){x[i] = p->flag;p = p->parent;}cout << "\n解向量为:< ";for (int i = 0; i < NUM_GOODS; i++)cout << x[i] << " ";cout << ">" << endl;cout << "背包可装入最大价值为:" << maxValue->value << endl;}int main(){initGoods();branchAndBound();printResult();//	system("pause");return 0;}
上一篇:LeetCode513. 找树左下角的值


下一篇:倍增求LCA