【JZOJ4224】食物【背包】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/86657108

题目大意:

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


思路:

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


m m 种运载工具,载重 x i x_i ,费用 y i y_i ,运输次数 z i z_i 。。。
这和第一问有什么区别嘛。。。
还是一个完全背包。跑一遍就可以得到答案了。
注意判断 T A T TAT 的情况。


代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/86657108