HDU 5445 Food Problem(多重背包)

Description
n种点心,每种点心有一定的能量t,体积u和数量v,现在要用m种卡车搬运这些点心,每种开车有一定的容量x,花费y和数量z,点心可以分割但选一块就要都选,现在问将运送总能量不小于p的点心的最小花费
Input
第一行一整数T表示用例组数,每组用例首先输入三个整数n,m,p分别表示点心种类数,车的种类数以及目标能量值,之后n行每行三个整数ti,ui,vi表示第i种点心你的能量值,体积和数量,之后m行每行三个整数xi,yi,zi表示第i种卡车的容量,花费和数量
(T<=10,1<=n,m<=200,0<=p<=50000,1<=ti,ui,vi,xi,yi,zi<=100)
Output
对于每次用例,问运送总能量不小于p的点心所需的最小花费,如果没有合法运送方案或者最小花费大于50000则输出TAT
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
Solution
做两遍多重背包,第一遍对点心,求出总能量不小于p的最小体积minv,第二遍对卡车,求出总容积不小于minv的最小花费minc,第一遍背包上限p+100,第二遍背包上限50000,复杂度可以接受
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 55555
int T,n,m,p,t[222],u[222],v[222],x[222],y[222],z[222],dp[maxn];
int res,a[maxn],b[maxn];
int Solve(int n,int v[],int w[],int num[])
{
    int sum=0;
    for(int i=1;i<=n;i++)sum+=num[i]*v[i];
    res=0;
    for(int i=1;i<=n;i++)
    {
        int k=1;
        while(k<num[i])
        {
            a[res]=k*v[i],b[res++]=k*w[i];
            num[i]-=k;
            k*=2;
        }
        if(num[i])a[res]=num[i]*v[i],b[res++]=num[i]*w[i];
    }
    return sum;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1;i<=n;i++)scanf("%d%d%d",&t[i],&u[i],&v[i]);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&x[i],&y[i],&z[i]);
        int temp=Solve(n,t,u,v);
        if(temp<p)printf("TAT\n");
        else
        {
            int minv=INF;
            for(int i=1;i<maxn;i++)dp[i]=INF;
            dp[0]=0;
            //dp[j]表示前i个物品总能量为j所需要的最小体积 
            for(int i=0;i<res;i++)
                for(int j=p+100;j>=a[i];j--)
                {
                    dp[j]=min(dp[j],dp[j-a[i]]+b[i]);
                    if(j>=p)minv=min(minv,dp[j]);
                }
            temp=Solve(m,x,y,z);
            if(temp<minv)printf("TAT\n");
            else
            {
                memset(dp,0,sizeof(dp));
                int minc=INF;
                //dp[j]表示前i辆卡车花费为j的最大容积 
                for(int i=0;i<res;i++)
                    for(int j=50000;j>=b[i];j--)
                    {
                        dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
                        if(dp[j]>=minv)minc=min(minc,j);
                    }
                if(minc>50000)printf("TAT\n");
                else printf("%d\n",minc);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值