zoukankan      html  css  js  c++  java
  • codevs 5429 多重背包

    5429 多重背包

     

     时间限制: 1 s
     空间限制: 256000 KB
     题目等级 : 钻石 Diamond
     
    题目描述 Description

    你有一个容量为M的背包,和N种物品。

    每种物品都有三个属性,vi,wi,与ci,分别表示这种物品的体积、价值和件数。

    你的任务是,从这些所给物品中,选出若干件,其体积之和不能超过背包容量,并且使所选物品的权值的和最大。

    输入描述 Input Description

    第一行两个整数N,M

    接下来N行每行三个数vi,wi,ci描述第i件物品的属性

    输出描述 Output Description

    最大的权值和

    样例输入 Sample Input

    2 8

    2 100 4

    4 100 2

    样例输出 Sample Output

    400

    数据范围及提示 Data Size & Hint

    对于20%的数据,ci=1

    对于60%的数据,N,M<=500,ci<=100

    对于90%的数据,N,M<=3000

    对于100%的数据,N,M<=7000,ci<=5000,保证答案不超过2147483647

    改数据前二进制优化可过

    改数据后过不了 要用单调队列优化;

    f[i][j]表示前i个物品容量为j的最大值

    f[i][j]=max(f[i-1][k]+(j-k)/w[i]*v[i])

    变化以下

    f[i][j]=max(f[i-1][k]-k/w[i]*v[i]+j/w[i]*v[i])

    可以看出更新f[i][j]时只与k有关 单调队列维护f[i-1][k]-k/w[i]*v[i]的最大值即可

    /*
    二进制优化代码
    60分 超时 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100010 
    using namespace std;
    int n,m,tot;
    int f[maxn];
    int w[maxn],v[maxn];
    int main()
    {
        int i,j,k;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            int s=1;
            while(s<z)
            {
                tot++;
                w[tot]=x*s;
                v[tot]=y*s;
                z-=s;s*=2;
            }
            tot++;
            w[tot]=x*z;
            v[tot]=y*z;
        }
        for(i=1;i<=tot;i++)
        {
            for(j=m;j>=w[i];j--)
            f[j]=max(f[j],f[j-w[i]]+v[i]);
        }
        printf("%d
    ",f[m]);
        return 0;
    }
    /*
    单调队列优化 
    AC 第一次打...... WA了好久 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 50010
    using namespace std;
    int n,m,head,tail;
    int w[maxn],v[maxn],c[maxn];
    int f[maxn],g[maxn];
    int q[maxn],p[maxn];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
          scanf("%d%d%d",&w[i],&v[i],&c[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=m;j++)g[j]=0;
            for(int j=0;j<w[i];j++)
            {
                head=1;tail=0;g[j]=f[j];
                for(int k=j,t=0;k<=m;k+=w[i],t+=v[i])
                {
                    while(tail>=head&&f[k]-t>=q[tail]) tail--;
                    tail++; q[tail]=f[k]-t; p[tail]=k;
                    if((k-p[head])/w[i]>c[i]) head++;
                    g[k]=q[head]+t;
                }
            }
            for(int j=0;j<=m;j++)f[j]=g[j];
        }
        printf("%d
    ",f[m]);
        return 0;
    } 
  • 相关阅读:
    常用 Git 命令清单
    谈谈关于PHP的代码安全相关的一些致命知识
    九个Console命令,让 JS 调试更简单
    有趣的博客小工具
    利用fputcsv导出数据备份数据
    IT小天博客APP版本
    七牛云存储文件批量下载工具使用教程
    Mysql的常见几种错误:1045,1044
    我是一个线程
    两行代码快速创建一个iOS主流UI框架
  • 原文地址:https://www.cnblogs.com/dingmenghao/p/6001583.html
Copyright © 2011-2022 走看看