题解
- 题目大意:有n种食物,和m种交通工具,问在费用不超过50000和美味度大于等于p时,需要的最少的运输费
- 这显然是一个多重背包问题
- 设f[i]为食物大小为i的时候所能得到的最大美味度,转移显然,f[i]=min(f[i-u]+t)
- 再设g[i]为费用为i的时候所能得到的最大运输量,转移也显然,g[i]=min(g[i-y]+x)
- 最后的话,然后使f[g[i]]>=p的时候,ans取一个min就好了
- 这样跑的话,显然会T的飞起,考虑一下怎么优化
- 这题有三种优化:优先队列、二进制优化、吸氧优化(由于博主过于蒟蒻在这里只讲二进制优化)
- 二进制优化其实就是将其变成1、2、4、8、16....的形式
- 然后我们可以发现,这样的话,既可以将所有的状态给表示出来,也可以很有效的减少循环状态数、数组的大小
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 #define N 50010
5 using namespace std;
6 int n,m,p,ans,T,f[N],g[N];
7 void dp(int x,int y) { for (int i=20000;i>=x;i--) f[i]=max(f[i],f[i-x]+y); }
8 void dp1(int x,int y) { for (int i=50000;i>=x;i--) g[i]=max(g[i],g[i-x]+y); }
9 int main()
10 {
11 scanf("%d",&T);
12 while (T--)
13 {
14 scanf("%d%d%d",&n,&m,&p),memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
15 for (int i=1,t,u,w;i<=n;i++)
16 {
17 scanf("%d%d%d",&t,&u,&w);
18 for (int j=1;j<=w;w-=j,j*=2) dp(u*j,t*j);
19 if (w) dp(u*w,t*w);
20 }
21 for (int i=1,x,y,k;i<=m;i++)
22 {
23 scanf("%d%d%d",&x,&y,&k);
24 for (int j=1;j<=k;k-=j,j*=2) dp1(y*j,x*j);
25 if (k) dp1(y*k,x*k);
26 }
27 ans=0;
28 for (int i=1;i<=50000;i++) if (f[g[i]]>=p) { ans=i; break;}
29 if (ans) printf("%d\n",ans); else printf("TAT\n");
30 }
31 }