• 01背包问题


    //动态规划解决0-1背包问题
    template<class Type>

    void Knapsack(Type v,int w,int c,int n,Type **m)
    {
    int jMax=min(w[n]-1,c);
    for(int j=0;j<=jMax;j++)
    m[n][j]=0;
    for(int j=w[n];j<=c;j++)
    m[n][j]=v[n];
    for(int i=n-1;i>1;i--)
    {
    jMax=min(w[i]-1,c);
    for(int j=0;j<=jMax;j++)
    m[i][j]=m[i+1][j];
    for(int j=w[i];j<=c;j++)
    m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
    }
    m[1][c]=m[2][c];
    if(c>=w[1])
    m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
    }

    template<class Type>
    void Traceback(Type **m,int w,int c,int n,int x)
    {
    for(int i=1;i<n;i++)
    if(m[i][c]==m[i+1][c]) x[i]=0;
    else
    {
    x[i]=1;c-=w[i];
    }
    x[n]=(m[n][c])?1:0;
    }


    //回溯法解决0-1背包问题
    template<class Typew,class Typep>

    class Knap
    {
    friend Typep Knapsack(Typep*,Typew*,Typew,int);
    private:
    Typep Bound(int i);
    void Backtrack(int i);
    Typew c; //背包容量
    int n; //物品数
    Typew *w; //物品重量数组
    Typep *p; //物品价值数组
    Typew *cw; //当前重量
    Typep cp; //当前价值
    Typep bestp; //当前最优价值
    };



    template<class Typew,class Typep>
    void Knap<Typew,Typep>::Backtrack(int i)
    {
    if(i>n) //到达叶节点
    {

    bestp=cp;
    return;
    }
    if(cw+w[i]<=c) //进入左子树
    {

    cw+=w[i];
    cp+=p[i];
    Backtrack(i+1);
    cw-=w[i];
    cp-=p[i];
    }
    if(Bound(i+1)>bestp) //进入右子树
    Backtrack(i+1);

    }

    template<class Typew,class Typep>
    Typep 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]*cleft/w[i];
    return b;
    }


    class Object{
    friend int Knapsack(int *,int *,int,int);
    public:
    int operator<=(Object a)const
    {
    return (d>=a.d);
    }
    private:
    int ID;
    float d;
    };

    template<class Typew,class Typep>
    Typep Knapsack(Typep p[],Type2 w[],Typew c,int n)
    {
    //为Knap::Backtrack初始化
    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]=w[Q[i-1].ID];
    }
    K.cp=0;
    K.cw=0;
    K.c=c;
    K.n=n;
    K.bestp=0
    //回溯搜索
    K.Backtrack(1);

    delete []Q;
    delete []K.w;
    delete []K.p;
    return K.bestp;
    }


    //优先队列式分支界限法解决背包问题

    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 KKnap
    {
    friend Typep Knapsack(Typep*,Typew*,Typew,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>
    void KKnap<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 KKnap<Typew,Typep>::MaxKnapsack()
    {
    //优先队列式分支界限法,返回最大价值,bestx返回最优解
    //定义最大堆的容量为1000
    H=new MaxHeap<HeapNode<Typep,Typew>>(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[],Type2 w[],Typew c,int n,int bestx[])
    {
    //为Knap::Backtrack初始化
    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);

    KKnap<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]=w[Q[i-1].ID];
    }
    K.cp=0;
    K.cw=0;
    K.c=c;
    K.n=n;
    K.bestp=0
    //调用MaxKnapsack求问题的最优解
    Typep bestp=K.MaxKnapsack();

    for(int j=1;j<=n;j++)
    bestx[Q[j-1].ID]=K.bestx[j];
    delete []Q;
    delete []K.w;
    delete []K.p;
    delete []K.bestx;
    return bestp;

    }
    Live together,or Die alone!
  • 相关阅读:
    浏览器中跨域创建cookie的问题
    tomcat域名问题
    Hibernate saveOrUpdate方法到底是怎么执行的?
    Ajax提交后台中文乱码问题
    允许浏览器跨域访问web服务端的解决方案
    IntelliJ 有的时候移动滚动条后会自动回到光标所在位置的解决方法
    线程池
    Jackson转换对象为json的时候报java.lang.stackoverflowerror
    虚拟内存
    Linux下JDK安装笔记
  • 原文地址:https://www.cnblogs.com/hzhida/p/2354721.html
Copyright © 2020-2023  润新知