【JZOJ4224】食物【背包】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/4224
思路:
由于食物可以拆开运输,所以让食物美味度之和不小于p
和最少的价钱运输
这两个问是毫不相关
的。
那么就分开来看。种不同的食物,美味度,大小,数量,这不就是一道裸的完全背包吗!
设表示重量为的最大美味度,那么就可以用二进制拆分做出来前半问了。
种运载工具,载重,费用,运输次数。。。
这和第一问有什么区别嘛。。。
还是一个完全背包。跑一遍就可以得到答案了。
注意判断的情况。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=210;
const int M=50200;
int T,n,m,p,q,sum,ans,t[N],u[N],v[N],f[M],W[N*7],V[N*7];
int read()
{
int d=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9')
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
int main()
{
T=read();
while (T--)
{
memset(V,0,sizeof(V));
memset(W,0,sizeof(W));
memset(f,0,sizeof(f));
sum=0;
n=read(),m=read(),p=read();
for (register int i=1;i<=n;i++)
{
t[i]=read(),u[i]=read(),v[i]=read();
int j;
for (j=1;j<=v[i];j*=2) //二进制拆分
{
V[++sum]=t[i]*j;
W[sum]=u[i]*j;
v[i]-=j;
}
if (v[i])
{
V[++sum]=t[i]*v[i];
W[sum]=u[i]*v[i];
}
}
for (register int i=1;i<=sum;i++)
for (register int j=M-1;j>=W[i];j--)
f[j]=max(f[j],f[j-W[i]]+V[i]);
q=-1;
for (register int i=1;i<M;i++)
if (f[i]>=p) //求出满足美味度不小于p的最小价值
{
q=i;
break;
}
if (q<0) //不成立
{
printf("TAT\n");
for (int i=1;i<=m;i++) q=read(),q=read(),q=read();
//一定要把无用的读入读完!!!
continue;
}
/////////////////////////////////////////////////////////////////////
memset(V,0,sizeof(V));
memset(W,0,sizeof(W));
memset(f,0,sizeof(f));
sum=0;
for (register int i=1;i<=m;i++)
{
t[i]=read(),u[i]=read(),v[i]=read();
int j;
for (j=1;j<=v[i];j*=2)
{
V[++sum]=t[i]*j;
W[sum]=u[i]*j;
v[i]-=j;
}
if (v[i])
{
V[++sum]=t[i]*v[i];
W[sum]=u[i]*v[i];
}
}
for (register int i=1;i<=sum;i++)
for (register int j=50000;j>=W[i];j--) //最大花费50000
f[j]=max(f[j],f[j-W[i]]+V[i]);
ans=-1;
for (register int i=1;i<=50000;i++)
if (f[i]>=q)
{
ans=i;
break;
}
if (ans<0)
{
printf("TAT\n");
continue;
}
printf("%d\n",ans);
}
return 0;
}