zoukankan      html  css  js  c++  java
  • [总结] 单调队列优化多重背包学习笔记

    使用单调队列,可以把求解多重背包问题的复杂度进一步优化到 $O(NM)$

    把状态 j 按照除以 $V_i$ 的余数分组,对每一组分别进行计算,不同组之间的状态在阶段 i 不会互相转移。

    上代码

    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&v[i],&w[i],&c[i]);
        for(int u=0;u<v[i];u++){
            int maxp=(m-u)/v[i];
            l=1,r=0;
            for(int j=maxp-1;j>=std::max(maxp-c[i],0);j--){
                while(l<=r&&calc(q[r],u,i)<=calc(j,u,i)) r--;
                q[++r]=j;
            }
            for(int j=maxp;~j;j--){
                while(l<=r&&q[l]>j-1) l++;
                if(l<=r)   //这句不能忘!!
                   f[u+j*v[i]]=std::max(f[u+j*v[i]],f[u+q[l]*v[i]]+(j-q[l])*w[i]);
                if(j-c[i]-1>=0){
                    while(l<=r&&calc(q[r],u,i)<=calc(j-c[i]-1,u,i)) r--;
                    q[++r]=j-c[i]-1;
                }
            }
        }
    }

    代码中的几句话有必要解释一下

    for(int j=maxp-1;j>=std::max(maxp-c[i],0);j--)
    
    
    这里是预处理,为了让状态能够转移到 maxp,此后队头保存的一直是 j-1 ~ j-c[i] 的最大值
    while(l<=r&&q[l]>j-1) l++;  
    
    
    q[l]>j-1 的意义是不让 q[j] 转移到 q[j]
    if(j-c[i]-1>=0){
        while(l<=r&&calc(q[r],u,i)<=calc(j-c[i]-1,u,i)) r--;
            q[++r]=j-c[i]-1;
    }
    
    
    这里的目的是更新队尾,也就是随着 j 的减小,可以从更靠前的状态转移来,但是从 j-1 ~ j-c[i] 都已经在之前更新过队尾了,所以这里更新 j-c[i]-1 
  • 相关阅读:
    netcore---Program.cs配置相关信息,及读取配置信息
    js
    python3 openssl问题(贼有用)
    Flask+微信公众号开发(接入指南)
    运维角度处理跨域问题
    羞羞的Python模块包
    Nginx之伪404( root与alias )
    【深度学习】:梯度下降,随机梯度下降(SGD),和mini-batch梯度下降
    【深度学习】:小白也能看懂的卷积神经网络
    《剑指offer》5:替换空格
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/8798925.html
Copyright © 2011-2022 走看看