zoukankan      html  css  js  c++  java
  • 背包问题

    背包问题

    目前已经学了三种背包问题,是时候整理一下模版了

    01背包

    这是最基础的背包问题,即每件物品只能取一次,问背包能装的不超过容量的最大价值

    方程:dp[i][j]=max{dp[i-1][j],dp[i-1][j-w[i]]+val[i]}(j>=w[i])

        边界:dp[i][j]=dp[i-1][j](j<w[i]),dp[0][j]=0;

    空间优化:由于dp[i][]只与dp[i-1][]有关,所以可以用滚动数组或迭代成一维数组进行空间优化

      滚动数组:让i%2即可,就不贴代码了

      迭代转为一维数组:dp[j]=max(dp[j],dp[j-w[i]]+val[i]),此时j必须逆序遍历,关于为什么逆序在另一篇博客http://www.cnblogs.com/--560/p/4340764.html已经介绍的很清楚了,就不过多叙述了,这里只给代码

    memset(dp,0,sizeof(dp));
    for(int i=1;i<=N;i++){
          for(int j=M;j>=0;j--){
                if(j-w[i]>=0) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
          }
    }
    
    /* 由于j>=w[i],所以上述代码也可以这样写  */
    
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=N;i++){
          for(int j=M;j>=w[i];j--){
                dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
          }
    }
    01背包

    完全背包

    即有n种物品,每种物品有无限个,还是问背包能装的不超过容量的最大价值

    方程:dp[j]=max{dp[j-w[i]]+val[i],dp[j]} 方程和01背包表面上一样,但其实不一样,j必须顺序遍历;在另一篇博客已经解释的很清楚了,就不解释了,附链接http://www.cnblogs.com/--560/p/4345855.html

    dp[0]=0;
    for(int i=1;i<=N;i++){
        for(int j=M;j>=0;j--){
            if(j-w[i]>=0) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    
    /* 同样也可以写成这样 */
    dp[0]=0;
    for(int i=1;i<=N;i++){
        for(int j=M;j>=w[i];j--){
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    完全背包

    多重背包

    即每种物品数量有限,问题同上

    方法:用二进制优化并转为01背包,懒得写了,直接看下面的代码吧

    void ZeroOnePack(int weight,int val)
    {
        for(int i=cash;i>=weight;i--){
            dp[i]=max(dp[i],dp[i-weight]+val);
        }
    }
    
    void CompletePack(int weight,int val)
    {
        for(int i=weight;i<=cash;i++){
            dp[i]=max(dp[i],dp[i-weight]+val);
        }
    }
    
    void MultiPack(int weight,int val,int amount)
    {
        if(weight*amount>=cash) CompletePack(weight,val);//如果超过限制,当完全背包处理
        else{                //否则用二进制优化并转为01背包处理
            int k=1;
            while(k<amount){//按k=1,2,4,...的顺序分解amount,对分解后的部分按01背包处理
                ZeroOnePack(k*weight,k*val);
                amount-=k;
                k*=2;
            }
            ZeroOnePack(amount*weight,amount*val); //剩下部分也按01背包处理
        }
    }
    
    int main()
    {
        while(cin>>cash>>N){
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=N;i++){
                cin>>n[i]>>D[i];
                MultiPack(D[i],D[i],n[i]);
            }
            cout<<dp[cash]<<endl;
        }
        return 0;
    }
    多重背包
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    JS 中 new 操作符
    js清除浏览器缓存的几种方法
    一个自定义分享按钮
    解决windows下nginx中文文件名乱码
    sublime text 3 添加 javascript 代码片段 ( snippet )
    transition动画最简使用方式
    hammerjs jquery的选项使用方法,以给swipe设置threshold和velocity为例
    sublime text 3 的emmet 添加自定义 html 片段
    解决 placeholder 垂直不居中,偏上的问题
    Sublime Text 3 配置 sass
  • 原文地址:https://www.cnblogs.com/--560/p/4348813.html
Copyright © 2011-2022 走看看