• O(V*n)的多重背包问题


    多重背包问题:

      有n件物品,第i件价值为wi,质量为vi,有c1件,问,给定容量V,求获得的最大价值。

      

    朴素做法:

      视为0,1,2,...,k种物品的分组背包 [每组只能选一个]

      f[i][j]=Max(f[i][j-k*v[i]]+k*w[i])

      但是i,j,k都要枚举,复杂度为 n*V*k

    朴素做法的改进:

      因为发现用二进制可以表示1..k之内的所有数 [整数二进制打开后为01串,所以可以被二进制表示]

      所以将k个物品拆分成1,2,4...2^m,k-2^m   ( 其中2^m<=k<2^(m+1) ) 这些物品,然后变成01背包问题。

      但是n的数目增多了,复杂度为 n*V*logk

    利用单调队列的改进:

      1.我们可以发现每个容量都能表示成 v*x+d 的形式[ v表示当前考虑的物品的容量 ]

      2.在上一点的启发下,我们发现一个f[v*x+d]在考虑当前物品时,只能由f[v*y+d]转移而来。 [其中x-y<=k]。

      也就是说,对v取模的余数相同的容量之间才能互相转移,而且要求x-y<=k。又因为求的是最大值的转移,所以满足单调队列的适用性。

      于是乎,我们对于余数d相同的容量分别建一个单调队列,然后枚举x f[x*v+d],进行转移即可。

      

     1 #include<cstdio>
     2 #include<cstring>
     3 
     4 inline int in(){
     5     int x=0,flag=1;char ch=getchar();
     6     while(ch!='-' && (ch>'9' || ch<'0')) ch=getchar();
     7     if(ch=='-') flag=-1,ch=getchar();
     8     while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
     9     return x*flag;
    10 }
    11 
    12 int a[200005],b[200005],f[200005];
    13 int w,v,k,n,V,l,r;
    14 
    15 void insert(int x,int y){
    16     while(l<=r && b[r]<=y) r--;
    17     a[++r]=x; b[r]=y;
    18 }
    19 
    20 inline int Max(int a,int b){
    21     if(a>b) return a;return b;
    22 }
    23 
    24 int main(){
    25     n=in(),V=in();
    26     int Lim;
    27     for(int i=1;i<=n;i++){
    28         v=in();w=in();k=in();
    29         if(k==1){
    30             for(int j=V;j>=v;j--)
    31                 f[j]=Max(f[j],f[j-v]+w);
    32             continue;
    33         }
    34         else if(k<0){
    35             for(int j=v;j<=V;j++)
    36                 f[j]=Max(f[j],f[j-v]+w);
    37             continue;
    38         }
    39         if(V/v<k) k=V/v;
    40         for(int d=0;d<v;d++){
    41             l=1,r=0;Lim=(V-d)/v; 
    42             for(int x=0;x<=Lim;x++){
    43                 insert(x,f[x*v+d]-x*w);
    44                 if(a[l]<x-k) l++;
    45                 f[x*v+d]=b[l]+x*w;
    46             }
    47         }
    48     }
    49     printf("%d",f[V]);
    50     return 0;
    51 }
    View Code

    codevs 3269 混合背包

    AC通道:http://codevs.cn/problem/3269/

  • 相关阅读:
    自动驾驶技术其实是一个美丽的谎言
    自动驾驶技术其实是一个美丽的谎言
    Shoutem旨在成为React Native移动应用领域的WordPress
    Mongodb安装
    spring mvc记录各个controller访问开始结束时间,以及耗时时间 线程安全
    python 升级
    SpringMVC的拦截器Interceptor
    使用org.apache.tools.zip实现zip压缩和解压
    使用 ResponseBodyAdvice 拦截Controller方法默认返回参数,统一处理返回值/响应体
    Python爬虫入门教程 4-100 美空网未登录图片爬取
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/4852423.html
Copyright © 2020-2023  润新知