背包问题为例:
头文件
#ifndef KNAP_H #define KNAP_H #include <iostream> using namespace std; //0-1 knapsack backtrace #define MaxSize 100 //最多物品数 extern int limitw; //限制的总重量 extern int maxwv; //存放最优解的总价值 extern int maxw; extern int num_element; //实际物品数 extern int option[MaxSize]; // 存放最终解 extern int op[MaxSize]; //存放临时解 struct node { int weight; int value; }; //存放物品数组 extern node a[MaxSize]; void Knap(int i, int tw, int tv); // 0-1 knapsack branch bound extern int c; //限制的总重量 extern int num_knap; struct good_node; extern good_node good[MaxSize]; extern int best_node[MaxSize]; // node point extern int bestp; //max profit struct good_node { //kanp node int weight; int value; good_node() {} good_node(const good_node& a) { weight = a.weight; value = a.value; } good_node & operator =(const good_node &a) { weight = a.weight; value = a.value; } int operator >=(good_node &a) const { return (weight >= a.weight); } }; struct tree_node { int index; bool is_used; tree_node* parent; tree_node():parent(NULL), index(0), is_used(0) {} tree_node(const tree_node & t) { parent = t.parent; index = t.index; is_used = t.is_used; } tree_node & operator =(const tree_node & t) { parent = t.parent; index = t.index; is_used = t.is_used; } }; struct HeapNode { //heap node tree_node *node_ptr; int cw; int cp; int uprofit; HeapNode():node_ptr(NULL), cw(0), cp(0), uprofit(0) {} HeapNode(const HeapNode& h) { node_ptr = h.node_ptr; cw = h.cw; cp = h.cp; uprofit = h.uprofit; } HeapNode & operator =(const HeapNode& h) { node_ptr = h.node_ptr; cw = h.cw; cp = h.cp; uprofit = h.uprofit; } int operator >=(HeapNode &a) const { return (uprofit >= a.uprofit); } ~HeapNode(); }; class Heap { int capacity; int size; HeapNode *elem; public: Heap() {} Heap(int c, int s); void InsertH(HeapNode& x); HeapNode DeleteMaxH(); int get_size(); ~Heap(); }; int Bound(int i, int, int); void AddLiveNode(Heap &, tree_node* node_ptr, int cp, int cw, int up); void MaxKnapsack(); //dm #endif
#include "knap.h" // 0-1 kanp backtrace node a[MaxSize]; int limitw; //限制的总重量 int maxwv; //存放最优解的总价值 int maxw; int num_element; //实际物品数 int option[MaxSize]; // 存放最终解 int op[MaxSize]; void Knap(int i, int tw, int tv) { //考虑第i个物品 if(tw <= limitw) { if(i >= num_element) { //找到一个叶子结点 if (tv > maxwv) { //找到一个满足条件地更优解,保存它 cout << maxwv << endl; maxwv = tv; maxw= tw; for(int j = 0; j < num_element; j++) option[j] = op[j]; } } else { op[i] = 1; //选取第I个物品 Knap(i + 1, tw + a[i].weight, tv + a[i].value); op[i] = 0; //不选取第I个物品,回溯 Knap(i + 1, tw, tv); } } }分支限界:
#include "knap.h" int c; int num_knap; good_node good[MaxSize]; int best_node[MaxSize] = {0}; int bestp; HeapNode::~HeapNode() { //if(node_ptr != NULL) delete node_ptr; } Heap::Heap(int c, int s) { capacity = c; size = s; elem = new HeapNode[c]; } void Heap::InsertH(HeapNode& x) { int sindex = 0; for(int i = 0; i < size; ++i) { if(elem[i] >= x) { sindex = i; break; } } for(int i = size; i > sindex; --i) { elem[i] = elem[i - 1]; } elem[sindex] = x; ++size; } HeapNode Heap::DeleteMaxH() { return elem[--size]; } int Heap::get_size() { return size; } Heap::~Heap() { delete [] elem; } int Bound(int i, int cw, int cp) { //计算节点所相应价值的上界 int cleft = c - cw; //剩余容量 int b = cp; //价值上界 //以物品单位重量价值递减序装填剩余容量 while(i < num_knap && good[i].weight <= cleft) { cleft -= good[i].weight; b += good[i].value; i++; } if(i < num_knap) b += good[i].value * cleft / good[i].weight; if(i == num_knap) b+= good[i - 1].value * cleft / good[i - 1].weight; return b; } void AddLiveNode(Heap &h, tree_node* node_ptr, int cp, int cw, int up) { //将一个新的活结点插入到子集树和最大堆H中 HeapNode N; N.node_ptr = node_ptr; N.cp = cp; N.cw = cw; N.uprofit = up; h.InsertH(N); } void MaxKnapsack() { //优先队列式分支限界法,返回最大价值,bestx返回最优解 //定义对大堆得容量为1000 //初始化 int cw = 0; int cp = 0; int ubound ; Heap H(1000, 0); HeapNode N; tree_node* parent = NULL; //搜索子集空间树 int i = 0; //node point ubound = Bound(i, cp, cw); //价值上界 while(H.get_size() >= 0) { if(i == num_knap) { //update bestp, best_node int tmp_bestp = 0; int tmp_best_node[MaxSize] = {0}; while(parent != NULL) { int index = parent->index; bool is_used = parent->is_used; if(is_used) { tmp_best_node[index] = 1; tmp_bestp += good[index].value; } parent = parent->parent; } if(tmp_bestp > bestp) { bestp = tmp_bestp; for(int j = 0; j < num_knap; ++j) best_node[j] = tmp_best_node[j]; } } else { //检查当前扩展结点的左儿子节点 int tw = cw + good[i].weight; if(tw <= c) { //左儿子节点为可行结点 ubound = Bound(i, cp, cw); if(ubound >= bestp) { tree_node *tmp = new tree_node(); tmp->parent = parent; tmp->index = i; tmp->is_used = true; AddLiveNode(H, tmp, cp + good[i].value, cw + good[i].weight, ubound); } } //检查当前扩展结点的右儿子节点 ubound = Bound(i + 1, cp, cw); if(ubound >= bestp) { tree_node *tmp = new tree_node(); tmp->parent = parent; tmp->index = i; tmp->is_used = false; AddLiveNode(H, tmp, cp, cw, ubound); } } //取下一扩展结点 if(H.get_size() == 0) break; N = H.DeleteMaxH(); parent = N.node_ptr; i = parent->index + 1; cw = N.cw; cp = N.cp; } }测试:
#include <cstdlib> #include <iostream> #include "knap.h" using namespace std; int main(int argc, char *argv[]){ //0-1 knapsack backtrace num_element = 3; //3物品 a[0].weight = 16;a[0].value = 45; a[1].weight = 15;a[1].value = 25; a[2].weight = 15;a[2].value = 25; //a[3].weight=1;a[3].value=1; cout << a[0].weight << ',' << a[0].value << endl; maxwv = 0; maxw = 0; limitw = 30; //限制重量不超过30 Knap(0, 0, 0); cout << "最佳装填方案是:" << endl; for(int j = 0; j < num_element; j++) if(option[j] == 1) cout << "第"<< j + 1 << "种物品" << endl; cout << "总重量=" << maxw << ",总价值=" << maxwv << endl; //0-1 knapsack branch bound c = 30; num_knap =3; good[0].weight = 16;good[0].value = 45; good[1].weight = 15;good[1].value = 25; good[2].weight = 15;good[2].value = 25; bestp = 0; MaxKnapsack(); //cout << Bound(1, 0, 0) << endl; for(int i = 0; i < num_knap; ++i) cout << best_node[i] << ','; cout << endl; cout << bestp << endl; system("PAUSE"); return EXIT_SUCCESS; }