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;
} 
原文地址:https://www.cnblogs.com/dingmenghao/p/6001583.html