zoukankan      html  css  js  c++  java
  • 单调队列优化多重背包 洛谷P1776 宝物筛选

    题目链接:https://www.luogu.org/problem/P1776

    首先我们知道单调队列,就是在区间移动时动态维护区间的最值

    单调队列优化的主要思想就是分组更新,因为w[i] w[i]w[i]是成倍增加的

    对于当前为w的体积,我们可以按它的余数分w组,即0,1....w-1

    同一个余数的在一组

    每组的转移是不影响的,也就是说单独转移

    f[i][5w]=max(f[i1][4w]4v,f[i1][3w]3v,f[i1][2w]2v,f[i1][w]v,f[i1][0])

    f[i][4w]=max(f[i1][3w]3v,f[i1][2w]2v,f[i1][w]v,f[i1][0])

    如上所示,每一个都可能有其组内前几个更新来,且不确定是哪个更新的,所以就可以用单调队列优化啦,维护区间的最大值。区间长度就是物品的个数num

    原来的状态转移方程为:f[i][j]=max(f[i1][j],f[i1][jkw[i]]+kv[i])

    现在的状态转移方程为:f[i][j]=max(f[i-1][d+j*w]-j*v,f[i-1][j])+a*v.(a=W/w)

    即原方程减的越少,等价于现在这个方程加的越多,所以区间可以从头移动到尾。(原方程选择数目是从左开始,对应现方程就是从右开始)

    看的几篇博客:背包九讲详解版

    https://blog.csdn.net/qq_40679299/article/details/81978770

    https://www.cnblogs.com/-guz/p/9866118.html

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int inf=1<<30;
    const int maxn=4e4+7;
    int dp[maxn],q[maxn],p[maxn];
    int main(){
        int n,W;cin>>n>>W;
        int ans=0;
        for(int i=1;i<=n;i++){
            int v,w,num;scanf("%d%d%d",&v,&w,&num);
            if(w==0)ans+=v*num;
            num=min(W/w,num);//最大能够承载的该物品的数量 
            for(int d=0;d<w;d++){//枚举重量的余数 
                int head=0,tail=0;
                int k=(W-d)/w;//我们转换后的表达式为dp[d+k*w]-k*v,所有我们要保证d+k*w<=W 
                for(int j=0;j<=k;j++){
                    while(head<tail&&dp[d+j*w]-j*v>=q[tail-1])tail--;
                    q[tail]=dp[d+j*w]-j*v;p[tail++]=j;
                    while(head<tail&&p[head]<j-num)head++;
                    dp[d+j*w]=max(dp[d+j*w],q[head]+j*v);
                } 
            }
        }
        cout<<dp[W]+ans<<endl;
        return 0;
    } 
  • 相关阅读:
    HDU 2544 (Djikstra)
    HDU 1237(表达式求值)
    HDU1690 (Floyd)
    《大道至简》读后感
    第6周总结
    第8周总结
    第7周总结
    第四周总结
    第5周总结
    java程序
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11350135.html
Copyright © 2011-2022 走看看