今天忽然想在C++中使用优先队列,印象中比较麻烦,翻了一下很久以前写的一段程序,贴上来。 代码的主要功能就是0/1背包问题如何用优先队列的分枝限界算法实现。【实现部分主要参考了王晓东那本书上的算法】 #include <queue> #include <iostream> #include <algorithm> #include <functional> using namespace std; class Object { friend int Knapsack(int*, int*, int, int, int*); friend struct compValue; friend struct comp; public: int operator <= (Object a) const { return (d >= a.d); } private: int ID; double d;//单位重量的价值 }; class Knap; class bbnode { friend Knap; friend int Knapsack(int*, int*, int, int, int*); private: bbnode* parent; bool lchild; }; class HeapNode { friend Knap; public: //operator int() const //{ // return uprofit; //} bool operator >(const HeapNode& hn) const {//以价值上界作为优先级 return uprofit > hn.uprofit; } private: int uprofit,//价值上界 profit;//相应的价值 int weight;//结点相应的重量 int level;//活结点在子集树中所处的层次 bbnode* ptr;// }; template<class CompType> class CompValue { public: typedef typename CompType::first_argument_type first_argument_type; typedef typename CompType::second_argument_type second_argument_type; typedef typename CompType::result_type result_type; //从模板中得到第一个参数类型,第二个参数类型,返回类型 CompValue():InnerCT(){ }//比较法则 result_type operator()(const first_argument_type* P1, const second_argument_type* P2) const { return InnerCT(*P1,*P2); }//起作用的函数 private: CompType InnerCT;//比较法则保存为私有成员 }; class Knap { friend int Knapsack(int*, int*, int, int, int*); public: int MaxKnapsack(); private: priority_queue<HeapNode*, vector<HeapNode*>, CompValue<greater<HeapNode> > >H;//H的优先级根据compValue来决定 int Bound(int i); void AddLiveNode(int up, int cp, int cw, bool ch, int level); bbnode *E;//指向扩展结点的指针 int c;//背包的容量 int n;//物品的数目 int *w;//重量数组 int *p;//价值数组 int cw;//当前装包容量 int cp;//当前已获得的价值 int *bestx;//最优解 }; //计算结点所相应价值的上界 int Knap::Bound(int i) { int cleft = c - cw;//剩余容量 int b = cp; //b是价值上界,初始值为已经得到的价值 while (i <= n && w[i] <= cleft) { cleft -= w[i]; b += p[i]; i++; } if (i <= n) b += p[i] / w[i] * cleft; return b; } //将一个新的活结点插入到子集树和优先队列中 void Knap::AddLiveNode(int up, int cp, int cw, bool ch, int level) { bbnode *b = new bbnode; b->parent = E; b->lchild = ch; HeapNode* N = new HeapNode; N->uprofit = up; N->profit = cp; N->weight = cw; N->level = level; N->ptr = b; H.push(N); } int Knap::MaxKnapsack() { int i = 1; E = 0; cw = cp = 0; int bestp = 0; int up = Bound(1); while (i != n + 1) { //检查当前扩展结点的左儿子结点 int wt = cw + w[i]; if (wt <= c)//左儿子结点是可行结点 { if (cp + p[i] > bestp) bestp = cp + p[i]; AddLiveNode(up, cp + p[i], cw + w[i], true, i + 1); } //检查当前扩展结点的右儿子结点 up = Bound(i + 1); if (up >= bestp)//右儿子结点可能存在最优解 { AddLiveNode(up, cp, cw, false, i + 1); } //取下一扩展结点 HeapNode* N = H.top(); H.pop(); E = N->ptr; cw = N->weight; cp = N->profit; up = N->uprofit; i = N->level; }//while bestx = new int[n + 1]; for (int j = n; j > 0; --j) { bestx[j] = E->lchild; E = E->parent; } return cp; } struct comp { bool operator ()(Object a, Object b) { return a.d > b.d; } }; //首先,将各物品按照单位重量价值从大到小进行排序; //然后,调用MaxKnapsack函数对子集树的优先队列式进行分支限界搜索 int Knapsack(int p[], int w[], int c, int n, int bestx[]) { //initialize int W = 0; // knapsack's total weight int P = 0; Object* Q = new Object[n]; for (int i = 0; i < n; ++i) { Q[i].ID = i + 1; Q[i].d = 1.0 * p[i + 1] / w[i + 1]; P += p[i + 1]; W += w[i + 1]; } if (W <= c)//如果足够装,全部装入 return P; //else sort(Q, Q + n, comp()); //for (int i = 0; i < n; ++i)//after sorted //{ // cout << Q[i].d << endl; //} Knap K; K.p = new int[n + 1]; K.w = new int[n + 1]; for (int i = 0; i < n; ++i) { K.p[i + 1] = p[Q[i].ID]; K.w[i + 1] = w[Q[i].ID]; } K.cp = 0; K.cw = 0; K.c = c; K.n = n; int bestp = K.MaxKnapsack(); for (int i = 0; i < n; ++i) { bestx[Q[i].ID] = K.bestx[i + 1]; } delete []Q; delete []K.w; delete []K.p; delete []K.bestx; return bestp; } int main() { int w[17] = { 0, 2, 3, 4, 7, 3, 2, 6, 3, 4, 5, 4, 3, 6, 2, 1, 1}; int p[17] = { 0, 1, 2, 5, 12, 4, 4, 5, 4, 7, 12, 6, 2, 7, 8, 1, 1 }; int c = 12; int n = 16; int *a = new int[17]; int maxp = Knapsack(p, w, c, n, a); cout << "最佳方案为: " << endl; for (int i = 1; i < 17; ++i) { if (a[i]) cout << i << " :" << "重量= " << w[i] << ",价值=" << p[i] << endl; } cout << "最优值=:" << maxp << endl; return 0; }