JZOJ 4224.食物

Description

这里写图片描述

Input

第一行一个数test,表示有test组数据。
对于每组数据,第一行有3个整数n,m,p.
接下来n行,每行3个整数t,u,v,描述一种食物。
最后m行,每行3个整数x,y,z,描述一种运载工具。

Output

对于每组数据,输出辉夜想知道的答案。注意存在无解的情况。

Sample Input

4
1 1 7
14 2 1
1 2 2
1 1 10
10 10 1
5 7 2
5 3 34
1 4 1
9 4 2
5 3 3
1 3 3
5 3 2
3 4 5
6 7 5
5 3 8
1 1 1
1 2 1
1 1 1

Sample Output

4
14
12
TAT

Data Constraint

test不会很大。
对于前20%的数据,n,m≤20.
对于前50%的数据,n,m≤30,ti,ui,vi,xi,yi,zi≤10.

Solution

我们看到这道题目很显然是背包问题,但是这道题的特别点在于食物可以被分开。那么只需要运输空间大于食物所需空间就能运输成功。

所以我们要打2个背包。
①求出美味度≥p的最小的食物的大小a1.
我们用g[i]表示当前美味度为i所需空间的大小。
假如费用i≥p则判断、用g[i]更新a1的值。
②求出可以装a1这么大的食物需要多少费用。
设f[i,k]表示装到第i件物品,所需费用为k所需最大空间。
如果f[i,k]≥a1,则证明我们运输当前的食物的美味度已经≥p了,那么>k的情况就不用讨论了。

对于拆分食物的问题,我们可以将食物总份数分为1,2,4…最后一个为总份数-(1+2+4+…)。
就像这样

        for i:=1 to n do
        begin
            readln(t,u,vv);//t,u,vv对应题目中的t,u,v.
            k:=1;
            while vv>k do
            begin
                inc(v[0]);
                v[v[0]]:=k*t;
                w[v[0]]:=k*u;
                vv:=vv-k;
                k:=k*2;
            end;
            if vv>0 then//如还有剩余,则将剩余的也当成一块进行运输
            begin
                inc(v[0]);
                v[v[0]]:=vv*t;
                w[v[0]]:=vv*u;
            end;
        end;

Code

var v,w:array[0..2000] of longint;
    x,y,z:array[0..200] of longint;
    g:array[0..50101] of longint;
    f:array[0..201,0..50101] of longint;
    _,ans,a1,p,i,j,k,l,n,m,t,u,vv,mk:longint;
function max(a,b:longint):longint;
begin
    if a>b then exit(a) else exit(b);
end;
function min(a,b:longint):longint;
begin
    if a<b then exit(a) else exit(b);
end;
begin
    readln(_);
    while _>0 do
    begin
        dec(_);
        fillchar(v,sizeof(v),0);
        fillchar(w,sizeof(w),0);
        fillchar(g,sizeof(g),127);
        fillchar(f,sizeof(f),0);
        a1:=maxlongint;
        ans:=0;
        readln(n,m,p);
        mk:=p;
        for i:=1 to n do
        begin
            readln(t,u,vv);
            if t>mk then mk:=t;
            k:=1;
            while vv>k do
            begin
                inc(v[0]);
                v[v[0]]:=k*t;
                w[v[0]]:=k*u;
                vv:=vv-k;
                k:=k*2;
            end;
            if vv>0 then
            begin
                inc(v[0]);
                v[v[0]]:=vv*t;
                w[v[0]]:=vv*u;
            end;
        end;
        for i:=1 to m do readln(x[i],y[i],z[i]);
        g[0]:=0;
        for i:=1 to v[0] do
            for j:=mk+100 downto v[i] do
            begin
                g[j]:=min(g[j],g[j-v[i]]+w[i]);
                if j>=p then a1:=min(a1,g[j]);
            end;
        if a1>=2139062143 then
        begin//这时我们找不到a1,这说明无法获得p的美味度。
            writeln('TAT');
            continue;
        end;
        ans:=maxlongint;
        for i:=1 to m do
            for j:=0 to z[i] do
                for k:=1 to 50000 do
                    if j*y[i]<=k then
                    begin
                        f[i,k]:=max(f[i,k],f[i-1,k-j*y[i]]+x[i]*j);
                        if f[i,k]>=a1 then
                        begin
                            ans:=min(ans,k);
                            break;
                        end;
                    end;
        if ans>50000 then writeln('TAT') else writeln(ans);//这个就不用说了,当前最小费用已经大于50000.
    end;
end.

——2016.2.16

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值