• codevs 3269 混合背包


    题目描述 Description

      背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?

    输入描述 Input Description

      第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限

    输出描述 Output Description

      1个数Ans表示所装物品价值的最大值

    样例输入 Sample Input

      2 10

      3 7 2

      2 4 -1

    样例输出 Sample Output

      22

    数据范围及提示 Data Size & Hint

      对于100%的数据,V <= 200000 , N <= 200

     题解:01+多重+完全背包。多重背包必须加二分制优化。不然全部超时。

              二分制优化:将第i件物品分为若干件物品,其中每件物品都有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数,是这些系数分别为1,2,4,...2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。而这些数字可以组合成1~n[i]内的所有数字。

                       例如12,可将其分为1,2,4,5.

    #include<cstdio>
    #include<iostream>
    #define N 210
    #define V 200100
    using namespace std;
    int n,v;
    int vi[N],wi[N],mi[N],f[V]={0};
    int main()
    {
        scanf("%d%d",&n,&v);
        for (int i=1;i<=n;i++) scanf("%d%d%d",&vi[i],&wi[i],&mi[i]);
        for (int i=1;i<=n;i++)
          {
               if (mi[i]==-1)//完全背包 
                 for (int j=vi[i];j<=v;j++) f[j]=max(f[j],f[j-vi[i]]+wi[i]);
               else  
                 {
                    for (int k=1;k<=mi[i];k++)//01和多重背包 
                       for (int j=v;j>=vi[i];j--)
                          f[j]=max(f[j],f[j-vi[i]]+wi[i]);    
                 }
               
          }
        cout<<f[v]<<endl;
        return 0;
    }
    未加二分制的超时代码
    #include<cstdio>
    #include<iostream>
    #define N 210
    #define V 200100
    using namespace std;
    int n,v;
    int vi[N],wi[N],mi[N],f[V]={0};
    int main()
    {
        scanf("%d%d",&n,&v);
        for (int i=1;i<=n;i++) scanf("%d%d%d",&vi[i],&wi[i],&mi[i]);
        for (int i=1;i<=n;i++)
          {
               if (mi[i]==-1)
                 for (int j=vi[i];j<=v;j++) f[j]=max(f[j],f[j-vi[i]]+wi[i]);
               else  
                 {
                       int x=mi[i];
                       for (int k=1;k<=x;k<<=1)//二分制优化 
                       
                          {
                               for (int j=v;j>=vi[i]*k;j--)
                                 f[j]=max(f[j],f[j-vi[i]*k]+wi[i]*k); 
                               x-=k;   
                      }
                  if (x)
                    for (int j=v;j>=vi[i]*x;j--)
                      f[j]=max(f[j],f[j-vi[i]*x]+wi[i]*x);
                 }
          }
        cout<<f[v]<<endl;
        return 0;
    }
    加了二分制后的满分代码
  • 相关阅读:
    ListView -————不能不说的秘密
    良好的开端是成功的第一步———构建程序
    你所不知道的windows窗体
    数据库查询终结版2———分组——连接
    数据库的终结版查询————你想知道吗?
    《官神》浏览闲看笔记
    坚信梦想,奋勇前进!____OS小题狂刷2333
    众里寻他千百度,蓦然回首,却见写者优先算法,她在书本寂静处!
    生产消费问题扩展——三个并发进程R,M,P和一个共享的循环缓冲区B的并发控制
    多生产者-多消费者-环形缓冲区问题
  • 原文地址:https://www.cnblogs.com/sjymj/p/6005648.html
Copyright © 2020-2023  润新知