Description
Input
Output
Sample Input
4
1 1 7
14 2 1
1 2 2
1 1 10
10 10 1
5 7 2
5 3 34
1 4 1
9 4 2
5 3 3
1 3 3
5 3 2
3 4 5
6 7 5
5 3 8
1 1 1
1 2 1
1 1 1
Sample Output
4
14
12
TAT
Data Constraint
Solution
多重背包问题。
因为食物可以被分开运输,所以只要运输的总空间大于美味值大于等于p的所有食物所需要的空间之和即可。可以将问题分成两个部分:
- 选出美味度之和不小于p的食物并且要求空间最小
- 选出空间之和不小于第一步的结果并且费用尽可能的少。
第一步我们可以用多重背包轻松解决,但第一步的答案可能会很大,无法在第二问直接用背包。不妨将状态和结果互换,以需要的费用作为状态,而用最大的空间作为答案。至此,我们可以设f[i]表示美味度之和为i的食物所用的最少空间,g[i]表示费用为i时最大能装的空间。注意到最大的费用只有50000,所以是可行的。但是需要注意的一点是,当求f[i]时,因为p<=50000所以我们可能会以为最大的食物的美味值之和只用做到50000,但实际上要做到更大一点,因为有可能几个食物的美味值大于了50000,但空间却更小,所以我们就要做到50000再多加一个食物的美味度就够了(即做到的当前这个),因为若多选2个或以上虽然美味值增加了,但是空间一定会比选一个的要少。
最后,我们发现时间复杂度乘了一个test后,可能会很大,所以要加二进制拆分法或是单调队列优化多重背包,详细内容可自行在网上搜索或查看我的博客。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2100
using namespace std;
int T,n,m,p,t,u,v,x,y,z,st,tot,ans,a[N],b[N],f[50110],g[50010];
int read(){
int w=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return w*x;
}
void add(int x,int y,int z){//二进制拆分法优化
st=1;tot=0;
while(z>=st){
a[++tot]=st*x;
b[tot]=st*y;
z-=st;st<<=1;
if(z&&st>z) st=z;
}
}
int main(){
freopen("food.in","r",stdin);
freopen("food.out","w",stdout);
T=read();
while(T--){
memset(f,127,sizeof(f));
memset(g,0,sizeof(g));
f[0]=0;
n=read(),m=read(),p=read();
for(int i=1;i<=n;i++){
t=read(),u=read(),v=read();
add(t,u,v);
for(int j=1;j<=tot;j++)
for(int k=p+a[j];k>=a[j];k--) f[k]=f[k]>f[k-a[j]]+b[j]?f[k-a[j]]+b[j]:f[k];
/*for(int j=1;j<=v;j++)
for(int k=50000;k>=t;k--)
f[k]=min(f[k],f[k-t]+u);*/
//不加优化的多重背包
}
u=ans=50001;
for(int i=p;i<=p+100;i++) u=u>f[i]?f[i]:u;
if(u>50000){
printf("TAT\n");
for(int j=1;j<=m;j++) x=read(),y=read(),z=read();
continue;
}
for(int i=1;i<=m;i++){
x=read(),y=read(),z=read();
add(x,y,z);
for(int j=1;j<=tot;j++)
for(int k=ans;k>=b[j];k--){//比ans大的肯定更新不了答案,所以可以直接从ans开始枚举
g[k]=g[k-b[j]]+a[j]>g[k]?g[k-b[j]]+a[j]:g[k];
if(g[k]>=u) ans=k;
}
/*for(int j=1;j<=z;j++)
for(int k=50000;k>=y;k--){
g[k]=max(g[k],g[k-y]+x);
if(g[k]>=u) ans=k;
}*/
//不加优化的多重背包
}
printf(ans==50001?"TAT\n":"%d\n",ans);
}
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/86669291