• [HDU2191]多重背包


    多重背包暴力DP为$O(nV^2)$,n为物品个数,V为背包容量,二进制优化复杂度为$O(nVlog V)$。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1010;
     7 int T,n,m,v,w,tot,f[N];
     8 
     9 int main(){
    10     for (scanf("%d",&T); T--; ){
    11         scanf("%d%d",&m,&n);
    12         rep(i,0,m) f[i]=0;
    13         rep(i,1,n){
    14             scanf("%d%d%d",&v,&w,&tot);
    15             for (int j=1; tot>=j; tot-=j,j<<=1)
    16                 for (int k=m; k>=j*v; k--) f[k]=max(f[k],f[k-j*v]+j*w);
    17             if (!tot) continue;
    18             for (int k=m; k>=tot*v; k--) f[k]=max(f[k],f[k-tot*v]+tot*w);
    19         }
    20         printf("%d
    ",f[m]);
    21     }
    22     return 0;
    23 }
    二进制优化

    单调队列优化复杂度为$O(nV)$。

    单调队列的主要思想是从DP方程入手:$$f_{i+j imes v}=max{f_{i+k imes v}+(j-k) imes w}=max{f_{i+k imes v}-k*w}+j*w$$

    v为当前物品的代价,w为价值。j-tot<=k<=j,tot为当前物品的个数。

    发现所有转移都是在同一剩余系下做的,所以只要对每个剩余系分别维护一个单调队列即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1010;
     7 int T,n,m,v,w,tot,q1[N],q2[N],f[N];
     8 
     9 void DP(int v,int w,int tot){
    10     for (int i=0; i<v; i++){
    11         int st=0,ed=0; q1[0]=q2[0]=0;//单调队列,q1[]存队列内下标,q2[]存队列内的值
    12         for (int j=0; j<=(m-i)/v; j++){//f[i+j*v[i]]=max{f[i+k*v[i]]+k*w[i]}+j*w[i](j-tot<=k<=j)
    13             if (st<=ed && q1[st]<j-tot) st++;//j-tot<=k<=j
    14             int t=f[i+j*v]-j*w;//队列中存f[i+j*v]-j*w
    15             f[i+j*v]=max(f[i+j*v],q2[st]+j*w);//更新f[i+j*v]
    16             while (st<=ed && t>=q2[ed]) ed--;//将j放入队列
    17             q1[++ed]=j; q2[ed]=t;
    18         }
    19     }
    20 }
    21 
    22 int main(){
    23     freopen("hdu2191.in","r",stdin);
    24     freopen("hdu2191.out","w",stdout);
    25     for (scanf("%d",&T); T--; ){
    26         scanf("%d%d",&m,&n); int mx=0;
    27         rep(i,0,m) f[i]=0;
    28         rep(i,1,n) scanf("%d%d%d",&v,&w,&tot),DP(v,w,tot);
    29         rep(i,1,m) mx=max(mx,f[i]); printf("%d
    ",mx);
    30     }
    31     return 0;
    32 }
  • 相关阅读:
    C#中递归算法的总结
    C# 创建错误日志
    获取指定路径下所有PDF文件的总页数
    C# 将文件转为字符串和将字符串转为文件的方法
    如何获得应用程序的物理路径
    C#中获得文件夹下所有文件的两种方法
    C#中加密与解密
    MacOS系统使用Homebrew官方地址报错
    privoxy代理服务器配置
    Nginx 反向代理 502 permission denied 解决
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9552590.html
Copyright © 2020-2023  润新知