zoukankan      html  css  js  c++  java
  • 01背包分支限界

    算法描述:

      活结点优先队列中结点元素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;
    }
  • 相关阅读:
    UVALive 4329 Ping pong
    面试题——设计一个程序:运行报错Stack Overflow Error
    MongoDB 主从复制小实验
    我总结的18个非常好用的vim指令
    php性能优化
    error LNK2019: unresolved external symbol / error LNK2001: 无法解析的外部符号
    CopyU!v2 已经收录到腾讯软件管家!
    HDU 1498 50 years, 50 colors (行列匹配+最小顶点覆盖)
    汉语-词语-庸俗:百科
    汉语-成语-见笑大方:百科
  • 原文地址:https://www.cnblogs.com/xing901022/p/2759075.html
Copyright © 2011-2022 走看看