算法描述:node
活結點優先隊列中結點元素N的優先級由該結點的上界函數Bound計算出的值uprofit給出。ios
子集樹中以結點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; };
上界計算函數:spa
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; }
分支限界搜索函數:code
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; }
主要程序代碼:blog
測試中.....(暫時很差使)排序
#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; }