版权声明:喜欢请点个大拇指,感谢各位dalao。弱弱说下,转载要出处呦 https://blog.csdn.net/qq_35786326/article/details/85015143
题目:
分析:
比较容易看出来这是一道多重背包的题.但是朴素做法肯定过不了,需要优化.比较常见的优化是二进制法和单调队列.这道题用二进制法比较好处理
由于
中可能包含负数,所以需要对式子变形:
,因为要让背包的容积是最大的,所以
取
,那么
移项,可以得到背包的容积为
要最大化
这样变形后,
的取值范围就变成了
,就可以分解成二进制数来做了
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
#define ch cheap
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int max(int x,int y) {return x>y? x:y;}
int a[205],b[205],c[205],d[205];
int cnt=0,w[200005],v[200005],f[200005];
void yh(int num,int x,int y)
{
for(int i=1;i<=num;i*=2)
{
v[++cnt]=x*i;
w[cnt]=y*i;
num-=i;
}
if(num)
{
v[++cnt]=x*num;
w[cnt]=y*num;
}
return;
}
int main()
{
int n=read(),ans=0,m=0;
for(int i=1;i<=n;i++)
{
a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read();
b[i]-=a[i];
ans+=a[i]*d[i];
m-=c[i]*a[i];
}
for(int i=1;i<=n;i++)
yh(b[i],c[i],d[i]);
memset(f,-127/3,sizeof(f));
f[0]=0;
for(int i=1;i<=cnt;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<ans+f[m];
return 0;
}