0-1揹包-分支限界

算法描述: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; }
相關文章
相關標籤/搜索