zoukankan      html  css  js  c++  java
  • 背包模型

    01背包:从右往左(因为只能由上一个物品的状态退出,如果从左往右则前边的保存的已是装了这件物品的值)递推,放不放此物品

    完全背包:从左往右递推

    多重背包:二进制拆包,或用单调队列优化(应该不考吧看的不明白QAQ)

    装满背包:只把f[0]设为0

    分组背包:把有依赖关系的方程一组,然后在一个阶段了分别dp不取附件,取一个,取两个(只有主次依赖)

    二维费用:再加一维费用的循环

    混合背包模板

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 205
    using namespace std;
    int n,m,w[maxn],v[maxn],a[maxn],dp[200005];
    int main(){
        cin>>n>>m;
        int tw,tv,ta;
        for(int i = 1;i <= n;i++){
            scanf("%d%d%d",&tw,&tv,&ta);
            if(tw > m) n--;
            else{
                w[i] = tw;
                v[i] = tv;
                a[i] = ta;
            }
        }
        for(int i = 1;i <= n;i++){
            if(a[i] == -1){
                for(int j = w[i];j <= m;j++){
                    dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
                }
            }
            if(a[i] == 1){
                for(int j = m;j >= w[i];j--){
                    dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
                }
            }
            if(a[i] >  1){
                if(a[i] * w[i] >= m){
                    for(int j = w[i];j <= m;j++){
                        dp[j] = max(dp[j],dp[j-a[i]*w[i]]+a[i]*v[i]);
                    }
                    continue;
                }
                int k = 1;
                for(;k<a[i];){
                    for(int j = m;j >= w[i]*k;j--){
                        dp[j] = max(dp[j],dp[j-w[i]*k]+v[i]*k);
                    }
                    a[i] -= k;
                    k = k<<1;
                }
                for(int j = m;j >= w[i]*a[i];j--){
                    dp[j] = max(dp[j],dp[j-w[i]*a[i]]+v[i]*a[i]);
                }
            }
        }
        cout<<dp[m]<<endl;
        return 0;
    }

    优先队列优化

    #include<iostream>
    #include<algorithm>    
    int n,m,dp[200005],w[205],v[205],a[205];
    using namespace std;
    //“多重背包”通用模板
    const int MAX_V = 200005;
    //v、n、w:当前所处理的这类物品的体积、个数、价值
    //V:背包体积, MAX_V:背包的体积上限值
    //f[i]:体积为i的背包装前几种物品,能达到的价值上限。
    inline void pack(int f[], int V, int v, int n, int w)
    {
      if (n == 0 || v == 0) return;
      if (n == 1) {               //01背包
        for (int i = V; i >= v; --i)
          if (f[i] < f[i - v] + w) f[i] = f[i - v] + w;
        return;
      }
      if (n * v >= V - v + 1 || n == -1) {   //完全背包(n >= V / v)
        for (int i = v; i <= V; ++i)
          if (f[i] < f[i - v] + w) f[i] = f[i - v] + w;
        return;    
      }
    
      int va[MAX_V], vb[MAX_V];   //va/vb: 主/辅助队列
      for (int j = 0; j < v; ++j) {     //多重背包
        int *pb = va, *pe = va - 1;     //pb/pe分别指向队列首/末元素
        int *qb = vb, *qe = vb - 1;     //qb/qe分别指向辅助队列首/末元素  
        for (int k = j, i = 0; k <= V; k += v, ++i) {
          if (pe  == pb + n) {       //若队列大小达到指定值,第一个元素X出队。
            if (*pb == *qb) ++qb;   //若辅助队列第一个元素等于X,该元素也出队。 
            ++pb;
          }
          int tt = f[k] - i * w;
          *++pe = tt;                  //元素X进队
          //删除辅助队列所有小于X的元素,qb到qe单调递减,也可以用二分法
          while (qe >= qb && *qe < tt) --qe;
          *++qe = tt;              //元素X也存放入辅助队列        
          f[k] = *qb + i * w;      //辅助队列首元素恒为指定队列所有元素的最大值
        }
      }
    }
    
    
    int main(){
    
        cin>>n>>m;
        for(int i = 1;i <= n;i++){
            cin>>w[i]>>v[i]>>a[i];
        }
        for(int i = 1;i <= n;i++){
            pack(dp,m,w[i],a[i],v[i]);
        }
        cout<<dp[m];
        return 0;
    }
  • 相关阅读:
    桟错误分析方法
    gstreamer调试命令
    sqlite的事务和锁,很透彻的讲解 【转】
    严重: Exception starting filter struts2 java.lang.NullPointerException (转载)
    eclipse 快捷键
    POJ 1099 Square Ice
    HDU 1013 Digital Roots
    HDU 1087 Super Jumping! Jumping! Jumping!(动态规划)
    HDU 1159 Common Subsequence
    HDU 1069 Monkey and Banana(动态规划)
  • 原文地址:https://www.cnblogs.com/hyfer/p/5812448.html
Copyright © 2011-2022 走看看