abcd 多重背包

这里写图片描述
【数据规模与约定】
对于 20%的数据,N≤10,-2≤a[i]< b[i]≤2;
对于 60%的数据,N≤50, -20≤a[i]< b[i]≤20;
对于 100%的数据,
N≤200,-25≤a[i]< b[i]≤25,1≤c[i]≤20,0≤d[i] ≤10000
·
·
·
·
解法:
我一开始拿到这个题是很懵的。
·
原来是一个背包!
我们设A=Σe[i]*c[i],B=Σe[i]*d[i]。
然后我们发现对于每一个 i ,我们e[i]每增加1,A就增加c[i],B就增加d[i]。背包?多重背包?

因为e[i]=[a[i],b[i]]等价于[0,b[i]-a[i]]+a[i];,又因为∑e[i]*c[i]=0,∑b[i]*e[i],把这两个式子转换为,

∑(b[i]-a[i])*c[i]+∑a[i]*c[i]=0,∑(b[i]-a[i])*d[i]+∑a[i]*d[i]最大。

第一个式子又变为∑(b[i]-a[i])*c[i]=-∑a[i]*c[i],所以背包体积是-∑a[i]*c[i],c
是物品体积,d是物品价值。进行dp,二进制优化。

这个背包必须装满:需要装满就要初始化f[0]=0,f[1~m]=-INF

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring> 
#define LL long long
#define N 209
using namespace std;
int a[N],b[N],c[N],d[N],n;
LL f[100009],v[100009],z[100009],p,Vm,Cm;
void creat(int nn,int vv,int zz)
{
    for(int i=1;i<=nn;i*=2)//二进制拆分成01背包 
    {
        v[++p]=i*vv;//体积 
        z[p]=i*zz;//价值 
        nn-=i; 
    }
    if(nn) v[++p]=nn*vv,z[p]=nn*zz;
}
int main()
{
    memset(f,-127/3,sizeof(f));//初始化!
    f[0]=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        Vm-=a[i]*c[i];Cm+=a[i]*d[i];b[i]-=a[i];
    }
    for(int i=1;i<=n;i++) creat(b[i],c[i],d[i]);

    for(int i=1;i<=p;i++)
     for(int j=Vm;j>=v[i];j--)
      f[j]=max(f[j],f[j-v[i]]+z[i]);
    printf("%lld",f[Vm]+Cm);
    return 0;
}
原文地址:https://www.cnblogs.com/dfsac/p/7587802.html