zoukankan      html  css  js  c++  java
  • 多重背包优化

    多重背包优化

    二进制拆分

    18个物品可以拆成1,2,4,8,3倍物品,这样5个物品任意取可以得到1~18个物品的所有方案。

    时间复杂度是(O(nWlogP)),P是一种物品的最大数量

    #include <bits/stdc++.h>
    using namespace std;
    const int maxw=4e4+5;
    const int maxn=1e4+5;
    int dp[2][maxw];
    int v[maxn],w[maxn];
    int main () {
        int n,W;
        scanf("%d%d",&n,&W);
        int cnt=0;
        for(int i=1;i<=n;i++){
            int v1,w1,m1;
            scanf("%d%d%d",&v1,&w1,&m1);
            int j=1;
            while((1<<j)-1<m1){
                v[++cnt]=v1*(1<<(j-1));
                w[cnt]=w1*(1<<(j-1));
                j++;
            }
            j--;
            int rest=m1-((1<<j)-1);
            v[++cnt]=rest*v1;
            w[cnt]=rest*w1;
        }
        for(int i=1;i<=cnt;i++){
            int cur=i&1;
            for(int j=0;j<=W;j++)dp[cur][j]=dp[cur^1][j];
            for(int j=w[i];j<=W;j++){
                dp[cur][j]=max(dp[cur][j],dp[cur^1][j-w[i]]+v[i]);
            }
        }
        int ans=0;
        for(int j=0;j<=W;j++)ans=max(ans,dp[cnt&1][j]);
        printf("%d
    ",ans);
    }
    

    单调队列

    w:重量,v:价值,可以得到一般转移方程

    [f[j]=max(f[j−w∗k]+v∗k);(k<=c) ]

    (d=jmod w),(s=j/w)

    [f[j]=max(f[d+w∗k]−v∗k)+v∗s(s-k<=c) ]

    可以发现对j按模w的余数划分剩余类,dp的转移只会发生在每一个剩余类之内。因此可以枚举模数d,用单调队列维护一个大小为k的窗口的(f[d+w∗k]−v∗k)的最大值,这样每次转移都是O(1)的,总的背包的时间复杂度是O(n*W)

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e2+5;
    const int maxw=4e4+5;
    int dp[maxw];
    int v[maxn],w[maxn],m[maxn];
    int main () {
        int n,W;
        scanf("%d%d",&n,&W);
        int ans=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&v[i],&w[i],&m[i]);
            if(w[i]==0)ans+=v[i]*m[i];
            else m[i]=min(m[i],W/w[i]);
        }
        for(int i=1;i<=n;i++){
            if(w[i]==0)continue;
            for(int d=0;d<w[i];d++){//枚举余数
                int k=(W-d)/w[i];//状态数
                vector<int>qi(k+2),qv(k+2);//idx,value
                int l=1,r=0;
                for(int j=0;j<=k;j++){
                    while(r>=l&&dp[d+j*w[i]]-j*v[i]>=qv[r])r--;
                    qv[++r]=dp[d+j*w[i]]-j*v[i];
                    qi[r]=j;
                    while(r>=l&&qi[l]<j-m[i])l++;
                    dp[d+j*w[i]]=max(dp[d+j*w[i]],qv[l]+j*v[i]);
                }
            }
        }
        int maxx=0;
        for(int i=0;i<=W;i++)maxx=max(maxx,dp[i]);
        ans+=maxx;
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    CentOS7与CentOS8一些区别
    windows下bat脚本记录
    windows server AD增加自定义属性
    vsphere6.7为虚拟机添加硬盘报“目标数据存储 不在存储容器中。”错误
    linux 常用的命令
    CentOS7开机无法启动,报 Failed to load SELinux policy. Freezing错误
    SpringCloudAlibaba笔记06
    SpringCloudAlibaba笔记05
    接触CrackMe 第一个
    HOOK钩子
  • 原文地址:https://www.cnblogs.com/ucprer/p/14583120.html
Copyright © 2011-2022 走看看