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;
    }
  • 相关阅读:
    [机房测试]11.11
    题解——[AHOI2013]作业(莫队)
    [机房测试]11.7
    [机房测试]11.6
    [机房测试]11.5
    [机房测试]11.4
    [机房测试]10.29
    [机房测试]10.28
    初学SPFA
    神奇的游戏
  • 原文地址:https://www.cnblogs.com/hyfer/p/5812448.html
Copyright © 2011-2022 走看看