优先队列式分支限界法0-1背包

来源:互联网 发布:禁止软件联网 编辑:程序博客网 时间:2024/06/08 03:37
 
#include<iostream>   #include <algorithm>   #include "heap.h"using namespace std;   class Knap   {   public:       Knap(double *pp,double *ww,double cc,int nn)//构造函数       {           p=pp;           w=ww;           c=cc;           n=nn;           cw=0;           cp=0;   E=0;          bestx=new int[n+1]; H=init(100);     }       double knapsack();//找最优值的函数。       double Bound(int i);//边界函数   void AddLiveNode(double up,double cp,double cw,bool ch,int lev);int MaxKnapsack();    void output()//输出最佳路径       {           for(int i=1;i<=n;i++)               cout<<bestx[i]<<" ";           cout<<endl;       }    private:       double c;   //背包容量    int n;      //物品总数    double *w;   //物品重量数组    double *p;   //物品价值数组    double cw;   //当前背包重量    double cp;   //当前背包价值    bbnode *E;   //指向扩展结点的指针    int *bestx;   //最优解结构HeapQueue H;  };   class Object   {   public:       int ID;       double d;   };     int cmp(Object a,Object b)//定于排序类型。   {       return a.d>b.d;//降序   }     double Knap::Bound(int i)   {         Object *Q=new Object[n+1];       int j;       for(j=1;j<=n;j++)       {           Q[j].ID=j;           Q[j].d=1.0*p[j]/w[j];       }       sort(Q+1,Q+n+1,cmp);/*对数组Q排序。按cmp()方式排序。这里要注意是从Q[1]开始而不是从Q开始*/  /*这里的Object 数组其实可以只创建一次就可以了,像现在这样每次调用Bound()都要创建并且对其进行排序,浪费资源,有待改进*//*    for(j=1;j<=n;j++)          cout<<Q[j].ID<<" ";      cout<<endl;  */      double cleft=c-cw;       double b=cp;       while(i<=n&&w[Q[i].ID]<=cleft)       {           cleft-=w[Q[i].ID];           b+=p[Q[i].ID];           i++;       }       if(i<=n)           b+=1.0*p[Q[i].ID]*cleft/w[Q[i].ID];/*如果不能完整装入一个物品,则可以装入部分。*/      return b;   }     double Knap::knapsack()   {       /*分支判断,如果背包容量足够大,就不用再回溯搜索了。*/      int i;       double W=0;       double P=0;       for(i=1;i<=n;i++)       {           W+=w[i];           P+=p[i];       }       if(W<=c)   //如果背包够大的话那么最优解就是全部了。bestx[]=1;{for(int j=1;j<=n;j++)bestx[j]=1;return P;  }/*如果背包容量不够大,则有最有的方案,使用优先队列方法。*/      return MaxKnapsack();   } void Knap::AddLiveNode(double up,double cp,double cw,bool ch,int lev){bbnode *b=new bbnode;       b->parent=E;       b->LChild=ch;       HeapNode N;N.uprofit=up;N.profit=cp;N.weight=cw;       N.level=lev;    N.ptr=b;       InsertMax(N,H);   }int Knap::MaxKnapsack(){double bestp=0;//当前最优值double up=Bound(1);//价值上界//cout<<up<<endl;//输出为22int i=1;while(i != n + 1){//double wt=cw+w[i];//cout<<wt<<endl;if(cw+w[i]<=c){if(cp+p[i]>bestp)/*前面是cw+w[i]<=c,这里是当前价值加上这一物品的价值大于最优值时更新最优值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;            N=DeleteMax(H);   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;}int main()   {       int n=4;       double c=7;//背包容量   /*注意点,这里的数组p[]和w[]的第一个元素是-100,这是因为我在操作过程中都是从数组元素的1开始的,而我们知道数组中第一个元素是0号元素,所以我这里用-100填上*/      double p[]={-100,9,10,7,4};//物品价值       double w[]={-100,3,5,2,1};//物品重量       Knap k=Knap(p,w,c,n);       cout<<k.knapsack()<<endl;       k.output();       return 1;   }  
</pre><pre class="cpp" name="code">
struct bbnode   {       bbnode *parent;       bool LChild;   };     struct HeapNode   {       bbnode *ptr; //指向活结点在子集树中相应结点的指针    double weight;  //结点所相应的重量 double uprofit, //结点的价值上限  profit;  //结点所相应的价值    int level;   //活结点在子集树中所处的层序号};   /****************************************************************************/    /****************************************************************************/  typedef HeapNode ElemType;  #define MaxData 32767       typedef struct Heap   {       int capacity;       int size;       HeapNode *Elem;     }Heap,*HeapQueue;     HeapQueue init(int maxElem)   {       HeapQueue H=new Heap;       H->capacity=maxElem;       H->size=0;       H->Elem=new HeapNode[maxElem+1];    H->Elem[0].uprofit=MaxData;       return H;   }     void InsertMax(ElemType x,HeapQueue H)   {       int i;       for(i=++H->size;H->Elem[i/2].uprofit<x.uprofit;i/=2)           H->Elem[i]=H->Elem[i/2];//此时i还没有进行i/2操作       H->Elem[i]=x;   }     ElemType DeleteMax(HeapQueue H)   {       int i,child;       ElemType MaxElem,LastElem;          //存储最大元素和最后一个元素。       MaxElem=H->Elem[1];              //堆是从第1号元素开始的。       LastElem=H->Elem[ H->size-- ];    //这里自动让size减少了。       for(i = 1 ; i * 2 <= H->size ; i = child)       {           child=i * 2;           /*在节点有左右子树的时候,可能存在一个大一个小的情况,这时候我们就要找出最小的;            如果Child = H->Size则表明他没有右子树,这时候就没有必要比较了。          */          if(child != H->size && H->Elem[child+1].uprofit>H->Elem[child].uprofit)               child++;//找最大的子树           if(LastElem.uprofit < H->Elem[child].uprofit)               H->Elem[i]=H->Elem[child];       }       H->Elem[i]=LastElem;       return MaxElem;   }


0 0