因为甜品可以拆开,所以我们可以把问题转化成两次独立的多重背包,第一次求价值对应的最小体积,第二次求价值对应的最大体积,然后用第一次求得的体积在第二次的dp数组里找价值的最小值即可
这里偷懒只用了二进制优化,跑得挺慢
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e4 + 10;
const int INF = 0x3f3f3f3f;
int N, V, w[210], v[210], num[210], dp[maxn];
struct Node {
int w, v;
}node[maxn];
void pack(int flag) {
int n = 0;
for (int i = 1; i <= N; i++) {
int cnt = 0;
for (int j = 0; cnt + (1<<j) <= num[i]; j++) {
++n;
node[n].w = w[i]*(1<<j);
node[n].v = v[i]*(1<<j);
cnt += (1<<j);
}
if (cnt < num[i]) {
++n;
node[n].w = w[i]*(num[i]-cnt);
node[n].v = v[i]*(num[i]-cnt);
}
}
if (flag == 0) memset(dp, INF, sizeof(dp));
else memset(dp, 0, sizeof(dp));
dp[0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = V; j >= node[i].v; j--) {
if (flag == 0) dp[j] = min(dp[j], dp[j-node[i].v] + node[i].w);
else dp[j] = max(dp[j], dp[j-node[i].v] + node[i].w);
}
}
}
void solve() {
int n, m, p;
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &v[i], &w[i], &num[i]);
}
N = n;
V = 50000;
pack(0);
int t = INF;
for (int i = p; i <= V; i++) t = min(t, dp[i]);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &w[i], &v[i], &num[i]);
}
N = m;
V = 50000;
pack(1);
int ans = -1;
for (int i = 0; i <= V; i++) {
if (dp[i] >= t) { ans = i; break; }
}
if (ans == -1) printf("TAT\n");
else printf("%d\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) solve();
return 0;
}