• 背包问题


    背包问题

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

    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!
  • 相关阅读:
    Selenium 3 + BrowserMobProxy 2.1.4 模拟浏览器访问 (含趟坑)
    macOS Sierra WiFi connecting problem
    Accumulator<Long> implements of JavaSparkContext in Spark1.x
    写了一个Android动画的启动界面
    用C#简单实现了数据的封装
    关于JAVA数据结构中的栈操作
    写了一个关于将XML文件导入数据库的程序(C#,sql server)
    经典电影里的数学应用
    初步学习多线程操作,代码不是完美的,欢迎大牛指点(运行通过)
    写了一份统计网站(ASP.NET)日访问量的源码(保存至数据库,部分性能待优化),运行通过。
  • 原文地址:https://www.cnblogs.com/--560/p/4348813.html
Copyright © 2020-2023  润新知