【JZOJ4224】食物【背包】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/4224
在这里插入图片描述


思路:

由于食物可以拆开运输,所以让食物美味度之和不小于p最少的价钱运输这两个问是毫不相关的。
那么就分开来看。nn种不同的食物,美味度tit_i,大小uiu_i,数量viv_i,这不就是一道裸的完全背包吗!
fif_i表示重量为ii的最大美味度,那么就可以用二进制拆分做出来前半问了。


mm种运载工具,载重xix_i,费用yiy_i,运输次数ziz_i。。。
这和第一问有什么区别嘛。。。
还是一个完全背包。跑一遍就可以得到答案了。
注意判断TATTAT的情况。


代码:

#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;
}
posted @ 2019-01-26 14:40  全OI最菜  阅读(95)  评论(0编辑  收藏  举报