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; }
相关文章
相关标签/搜索