0-1背包-分支限界
算法描述:
活结点优先队列中结点元素N的优先级由该结点的上界函数Bound计算出的值uprofit给出。
子集树中以结点N为根的子树中任一结点的价值不超过N.profit。
可用一个最大堆来实现或节点优先队列。
N.weight 是结点N所相应的重量,N.profit是N所相应的价值,N.uprofit是结点N的价值上界,最大堆以这个值作为优先级。
class Object{ friend int Knapsack(int *,int *,int ,int ,int *); public: int operator <= (Object a) const { return (d >= a.d); } private: int ID; float d; }; template <class Typew,class Typep> class Knap; class bbnode{ friend Knap<int,int>; friend int Knapsack(int *,int *,int,int,int *); private: bbnode * parent; bool LChild; }; template <class Typew,class Typep> class HeapNode{ friend Knap<Typew,Typep>; public: operator Typep() const { return uprofit; } private: Typep uprofit,//结点价值上界 profit; Typew weight; int level;//活结点所相应的重量 bbnode * ptr; };
上界计算函数:
template <class Typew,class Typep> class Knap<Typew,Typep>::Bound(int i) { Typew cleft = c- cw;//剩余容量 Typep b = cp;//价值上界 //以物品单位重量价值递减序装填剩余容量 while(i<=n && w[i] <= cleft) { cleft -= w[i]; b += p[i]; i++; } //装填剩余容量装满背包 if(i<=n) b += p[i]/w[i] * cleft; return b; }
分支限界搜索函数:
template <class Typew,class Typep> Typep Knap<Typew,Typep>::MaxKnapsack() { //优先队列式分支限界法,返回最大价值,bestx返回最优解 //定义最大堆的容量为1000 H = new MaxHeap< HeapNode<Typew,Typep> >(1000); //为bestx分配存储空间 bestx = new int [n+1]; //初始化 int i=1; E= 0; cw = cp = 0; Typep bestp = 0; Typep up = Bound(1); //搜索子集空间树 while(i!=n+1)//非叶节点 { //检查当前扩展结点的左儿子结点 Typew 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<Typep,Typew> N; H->DeleteMax(N); E = N.ptr; cw = N.weight; cp = N.profit; up = N.uprofit; i = N.level; } //构造当前最优解 for(int j=n;j>0;j--) { bestx[j] = E->LChild; E = E->parent; } return cp; }
主要程序代码:
测试中.....(暂时不好使)
#include <iostream> #include <algorithm> class Object{ friend int Knapsack(int *,int *,int ,int ,int *); public: int operator <= (Object a) const { return (d >= a.d); } private: int ID; float d; }; template <class Typew,class Typep> class Knap; class bbnode{ friend Knap<int,int>; friend int Knapsack(int *,int *,int,int,int *); private: bbnode * parent; bool LChild; }; template <class Typew,class Typep> class HeapNode{ friend Knap<Typew,Typep>; public: operator Typep() const { return uprofit; } private: Typep uprofit,//结点价值上界 profit; Typew weight; int level;//活结点所相应的重量 bbnode * ptr; }; template <class Typew,class Typep> class Knap{ friend Typep Knapsack(Typep *,Typew *,Typew ,int ,int *); public: Typep MaxKnapsack(); private: MaxHeap<HeapNode<Typep,Typew> > * H; Typep Bound(int i); void AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int level); bbnode * E; Typew c; int n; Typew * w; Typep *p; Typew cw; Typep cp; int *bestx; }; template <class Typew,class Typep> class Knap<Typew,Typep>::Bound(int i) { Typew cleft = c- cw;//剩余容量 Typep b = cp;//价值上界 //以物品单位重量价值递减序装填剩余容量 while(i<=n && w[i] <= cleft) { cleft -= w[i]; b += p[i]; i++; } //装填剩余容量装满背包 if(i<=n) b += p[i]/w[i] * cleft; return b; } template <class Typep,class Typew> void Knap<Typep,Typew>::AddLiveNode(Typep up,Typep cp,Typew cw,bool ch,int lev) { //将一个新的活结点插入到子集树 和 最大堆 H中 bbnode *b = new bbnode; b->parent = E; b->LChild = ch; HeapNode<Typep,Typew> N; N.uprofit = up; N.profit = cp; N.weight = cw; N.level = lev; N.ptr = b; H->Insert(N); } template <class Typew,class Typep> Typep Knap<Typew,Typep>::MaxKnapsack() { //优先队列式分支限界法,返回最大价值,bestx返回最优解 //定义最大堆的容量为1000 H = new MaxHeap< HeapNode<Typew,Typep> >(1000); //为bestx分配存储空间 bestx = new int [n+1]; //初始化 int i=1; E= 0; cw = cp = 0; Typep bestp = 0; Typep up = Bound(1); //搜索子集空间树 while(i!=n+1)//非叶节点 { //检查当前扩展结点的左儿子结点 Typew 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<Typep,Typew> N; H->DeleteMax(N); E = N.ptr; cw = N.weight; cp = N.profit; up = N.uprofit; i = N.level; } //构造当前最优解 for(int j=n;j>0;j--) { bestx[j] = E->LChild; E = E->parent; } return cp; } template <class Typew,class Typep> Typep Knapsack(Typep p[],Typew w[],Typew c,int n,int bestx[]) { Typew W = 0; Typep P = 0; //按 单位重量价值 排序 Object * Q = new Object [n]; for(int i=1;i<=n;i++) { Q[i-1].ID = i; Q[i-1].d = 1.0*p[i]/w[i]; P += p[i]; W += w[i]; } if(W<=c) return P; Sort(Q,n); Knap<Typew,Typep> K; K.p = new Typep[n+1]; K.w = new Typew[n+1]; for(int i=1;i<=n;i++) { K.p[i] = p[Q[i-1].ID]; K.w[i] = p[Q[i-1].ID]; } K.cp = 0; K.cw = 0; K.c = c; K.n = n; Typep bestp = K.MaxKnapsack(); for(int j=1;j<=n;j++) { bestx[Q[i-1].ID] = K.bestx[j]; cout<<bestx[Q[i-1.ID]]<<endl; } delete [] Q; delete [] K.w; delete [] K.p; delete [] K.bestx; cout<<"最大价值为"<<bestp<<endl; return bestp; } int main() { int n,m; int w[100],p[100],best[100]; cout<<"请输入想要输入的物品个数 及 背包重量:"<<endl; cin>>n>>m; cout<<"请依次输入想要输入的物品重量 及 价值"<<endl; for(int i=0;i<n;i++) cin>>w[i]>>p[i]; Knapsack(w,p,m,n,best); return 0; }