题目
思路
因为食物是可以分开放的,所以我们可以分别计算两个问题。
1、食品美味程度达到
p
p
p。
2、选择运载工具使得费用最小且能装下这些食品。
那么第一个问题就是多重背包。
第二个问题也是多重背包,因为第一问的答案可能很大,那么我们就要把状态和答案调换,设
f
[
j
]
f[j]
f[j]为用了
j
j
j元用运载工具可以得到得最大空间。
然后二进制拆分或者单调队列优化就能过掉这题了。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, m, p;
int t[201], u[201], v[201], f[50001], V[1401], W[1401];
inline void solve() {
scanf("%d %d %d", &n, &m, &p);
int num = 0;
for (register int i = 1; i <= n; i++) {
scanf("%d %d %d", &t[i], &u[i], &v[i]);
for (register int j = 1; j <= v[i]; j *= 2) {
W[++num] = u[i] * j;
V[num] = t[i] * j;
v[i] -= j;
}
if (v[i]) {
W[++num] = u[i] * v[i];
V[num] = t[i] * v[i];
}
}
memset(f, 0xcf, sizeof(f));
f[0] = 0;
for (register int i = 1; i <= num; i++)
for (register int j = 50000; j >= W[i]; j--)
f[j] = std::max(f[j], f[j - W[i]] + V[i]);
int ans1 = 0;
for (register int i = 1; i <= 50000; i++)
if (f[i] >= p) {
ans1 = i;//满足美味程度达到p的最小空间
break;
}
if (!ans1) {
printf("TAT\n");
int a;
for (register int i = 1; i <= m; i++)
scanf("%d %d %d", &a, &a, &a);
return;
}
num = 0;
for (register int i = 1; i <= m; i++) {
scanf("%d %d %d", &t[i], &u[i], &v[i]);
for (register int j = 1; j <= v[i]; j *= 2) {
W[++num] = u[i] * j;
V[num] = t[i] * j;
v[i] -= j;
}
if (v[i]) {
W[++num] = u[i] * v[i];
V[num] = t[i] * v[i];
}
}
memset(f, 0xcf, sizeof(f));
f[0] = 0;
for (register int i = 1; i <= num; i++)
for (register int j = 50000; j >= W[i]; j--)
f[j] = std::max(f[j], f[j - W[i]] + V[i]);
int ans2 = -1;
for (register int i = 1; i <= 50000; i++)
if (f[i] >= ans1) {
ans2 = i;//满足空间需求的最小费用
break;
}
if (ans2 < 0) printf("TAT\n");
else printf("%d\n", ans2);
}
int main() {
int test;
scanf("%d", &test);
for (; test; test--, solve());
}