【五校联考3day1】食物

这题01背包,表示不知为何一眼切。。。
一维DP,每组数据两次DP。
算了,讲清楚一点吧。
我们对于每个u,v,d
将其拆成
1u,1v
2u,2v
4u,4v

d-(2k-1)u,d-(2k-1)v
例如d=17
我们便可以拆成:
1u,1v
2u,2v
4u,4v
8u,8v
2u,2v(这个是剩下的)
这样子就没错了。
然后就来一遍01背包搞搞就可以了。
详见看标:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,m,p,a[1410][2],b[1410][3];
int t,u,v,k,x,tot=0,cnt=0,f[50010],g[50010],big,ans;

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

int main()
{
	freopen("food.in","r",stdin);
//	freopen("food.out","w",stdout);
	T=read();
	while (T--)
	{
		n=read(),m=read(),p=read();
		tot=cnt=0;
		for (int i=1;i<=n;i++)
		{
			t=read(),u=read(),v=read(),k=1;
			while (v-k>=0)
			{
				a[++tot][0]=t*k,a[tot][1]=u*k;
				v-=k,k<<=1;
			}
			if (v) a[++tot][0]=t*v,a[tot][1]=u*v;
		}
		for (int i=1;i<=m;i++)
		{
			t=read(),u=read(),v=read(),k=1;
			while (v-k>=0)
			{
				b[++cnt][0]=t*k,b[cnt][1]=u*k;
				v-=k,k<<=1;
			}
			if (v) b[++cnt][0]=t*v,b[cnt][1]=u*v;
		}
		memset(f,10,sizeof(f)),f[0]=0;
		for (int i=1;i<=tot;i++)
		{
			for (int j=p-1;j>=p-a[i][0];j--)
				f[p]=min(f[p],f[j]+a[i][1]);
			for (int j=p-a[i][0]-1;j>=0;j--)
				f[j+a[i][0]]=min(f[j+a[i][0]],f[j]+a[i][1]);
		}
		big=f[p];
		if (big==f[p+1]) {puts("TAT"); continue;}
		memset(g,0,sizeof(g));
		for (int i=1;i<=cnt;i++)
		{
			for (int j=big-1;j>=big-b[i][1];j--)
				g[big]=max(g[big],g[j]+b[i][0]);
			for (int j=big-b[i][1]-1;j>=0;j--)
				g[j+b[i][1]]=max(g[j+b[i][1]],g[j]+b[i][0]);
		}
		for (int i=1;i<=50000;i++)
			if (g[i]>=big) {printf("%d
",i); break;}
	}
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11817636.html