题意:首先有n种点心,每种点心的t,u,v代表该点心每个所提供的能量,体积,数量。
然后有m中车,每种车的x,y,z代表这种车的容量,费用,数量。
又有一个p,问你所选的点心达到p的能量值的时候所需要的最少费用。(点心可以切割,即可以分开到每辆车里面,但是只要你选了一个,就整个点心都要放进车里)
因为点心师可以切割的,所以我们可以分两次dp,第一次先求出要达到p能量的时候需要的最小体积minv,第二次dp求就是要达到minv的的最小费用minc
还要注意的是,题目说最后的费用不能超过50000,复杂度可以接受
这里我用了类似多重背包的方法(写得挫比较慢)。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
#define ll long long
#define max(a,b) a>b?a:b
const int INF = 0x3f3f3f3f;
const int MAXN = 50010;
const int N = 205;
int dp[MAXN], pd[MAXN];
struct node{
int t,u;
void init(int _t, int _u){
t = _t, u =_u;
}
}de[N*N];
struct point{
int x,y,z;
void init(int _x, int _y){
x = _x, y = _y;
}
}ca[N*N];
int main(){
//freopen("in.txt","r",stdin);
int T, n, m, p;
int cot, cot2, mx, minc, minv;
int t, u, v, x, y, z;
scanf("%d",&T);
while(T--){
mx = 0;
minv = minc =INF;
cot = cot2 = 0;
memset(pd, 0, sizeof(pd));
scanf("%d%d%d",&n,&m,&p);
memset(dp,0x3f,sizeof(int)*(p+105));
for(int i = 1; i <= n; i++){
scanf("%d%d%d",&t, &u, &v);
int k = 1;
while(k < v){
de[cot++].init(k*t, k*u);
v -= k;
k *= 2;
}
if(v)de[cot++].init(v*t, v*u);
}
dp[0] = 0;
//第一次DP找出能达到p能量的最小体积
for(int i = 0; i < cot; i++){
for(int j = p+100; j >= de[i].t; j--){
dp[j] = min(dp[j], dp[j - de[i].t] + de[i].u);
if(j >= p){
if(minv > dp[j]){
minv = dp[j];
}
}
}
}
for(int i = 1; i <= m; i++){
scanf("%d%d%d",&x, &y, &z);
int k = 1;
mx += x*z;
while(k < z){
ca[cot2++].init(x*k,y*k);
z -= k;
k *= 2;
}
if(z)ca[cot2++].init(x*z,y*z);
}
if(mx < minv){
puts("TAT");
continue;
}
//第二次DP找出能达到最小体积的最小费用
for(int i = 0; i < cot2; i++){
for(int j = 50000; j >= ca[i].y; j--){
pd[j] = max(pd[j], pd[j-ca[i].y] + ca[i].x);
if(pd[j] >= minv){
minc = min(minc,j);
}
}
}
if(minc<=50000)printf("%d\n",minc);
else puts("TAT");
}
return 0;
}