题目链接:见这里
题意:首先有n种点心,每种点心的t,u,v代表该点心每个所提供的能量,体积,数量。然后有m中车,每种车的x,y,z代表这种车的容量,费用,数量。又有一个p,问你所选的点心达到p的能量值的时候所需要的最少费用。(点心可以切割,即可以分开到每辆车里面,但是只要你选了一个,就整个点心都要放进车里)

解法:因为点心是可以切割的,所以我们可以分两次dp,第一次先求出要达到p能量的时候需要的最小体积minv,第二次dp求就是要达到minv的的最小费用mincost,显然这就是个两次多重背包,但是我们按照普通的方法拆成01背包,显然复杂度是100*100*1e5显然是会爆炸的对吧,多以我们考虑二进制拆分,那么复杂度可以降为100*log100*50000是可以跑过去的。判断不合法就在第二个dp的时候来判断,这题就完了。开始写进制拆分写智障,WA了3发。

//HDU 5445

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100010;
struct node{
    int t, u;//能量,体积
    node(){}
    node(int t, int u) : t(t), u(u) {}
}Food[maxn*110], Car[maxn*100];

int dp1[maxn]; //dp1[i]表示能量为i可以达到的最小体积,注意初始化
int dp2[maxn]; //dp2[i]表示费用为i的时候可以达到的最小体积

int T, n, m, p, minv, mincost;

int main()
{
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &n, &m, &p);
        minv = mincost = inf;
        memset(dp1, 0x3f, sizeof(dp1));
        memset(dp2, 0, sizeof(dp2));
        int cnt1 = 0, cnt2 = 0;
        for(int i = 1; i <= n; i++){
            int t, u, v;
            scanf("%d%d%d", &t, &u, &v);
            //二进制拆分
            int k = 1;
            while(k < v){
                Food[cnt1++] = node(k * t, k * u); v-= k; k = k * 2;
            }
            if(v) Food[cnt1++] = node(v * t, v * u);
        }
        //第一次dp得到能达到p能量的最小体积
        dp1[0] = 0;
        for(int i = 0; i < cnt1; i++){
            for(int j = p + 100; j >= Food[i].t; j--){
                dp1[j] = min(dp1[j], dp1[j - Food[i].t] + Food[i].u);
                if(j >= p && minv >= dp1[j]){
                    minv = dp1[j];
                }
            }
        }
        for(int i = 1; i <= m; i++){
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            int k = 1;
            while(k < z){
                Car[cnt2++] = node(k * x, k * y); z -= k; k = k * 2;
            }
            if(z) Car[cnt2++] = node(z * x, z * y);
        }
        //第二次dp找出能达到最小体积的最小费用
        for(int i = 0; i < cnt2; i++){
            for(int j = 50000; j >= Car[i].u; j--){
                dp2[j] = max(dp2[j], dp2[j - Car[i].u] + Car[i].t);
                if(dp2[j] >= minv){
                    mincost = min(mincost, j);
                }
            }
        }
        if(mincost <= 50000) printf("%d\n", mincost);
        else puts("TAT");
    }
    return 0;
}