hdu5445 Food Problem(多重背包)(*)

题目链接
Food Problem
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1731 Accepted Submission(s): 544

Problem Description
Few days before a game of orienteering, Bell came to a mathematician to solve a big problem. Bell is preparing the dessert for the game. There are several different types of desserts such as small cookies, little grasshoppers and tiny mantises. Every type of dessert may provide different amounts of energy, and they all take up different size of space.

Other than obtaining the desserts, Bell also needs to consider moving them to the game arena. Different trucks may carry different amounts of desserts in size and of course they have different costs. However, you may split a single dessert into several parts and put them on different trucks, then assemble the parts at the game arena. Note that a dessert does not provide any energy if some part of it is missing.

Bell wants to know how much would it cost at least to provide desserts of a total energy of p (most of the desserts are not bought with money, so we assume obtaining the desserts costs no money, only the cost of transportation should be considered). Unfortunately the mathematician is having trouble with her stomach, so this problem is left to you.

Input
The first line of input contains a integer T(T≤10) representing the number of test cases.

For each test case there are three integers n,m,p on the first line (1≤n≤200,1≤m≤200,0≤p≤50000), representing the number of different desserts, the number of different trucks and the least energy required respectively.

The i−th of the n following lines contains three integers ti,ui,vi(1≤ti≤100,1≤ui≤100,1≤vi≤100) indicating that the i−th dessert can provide ti energy, takes up space of size ui and that Bell can prepare at most vi of them.

On each of the next m lines, there are also three integers xj,yj,zj(1≤xj≤100,1≤yj≤100,1≤zj≤100) indicating that the j−th truck can carry at most size of xj , hiring each one costs yj and that Bell can hire at most zj of them.

Output
For every test case output the minimum cost to provide the dessert of enough energy in the game arena if it is possible and its cost is no more than 50000. Otherwise, output TAT on the line instead.

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

Source
2015 ACM/ICPC Asia Regional Changchun Online
题意:n种点心,每种点心有一定的能量t,体积u和数量v,现在要用m种卡车搬运这些点心,每种开车有一定的容量x,花费y和数量z,点心可以分割但选一块就要都选,现在问将运送总能量不小于p的点心的最小花费
思路:算是复习了一下多重背包,都不怎么会了QAQ。
这里限制条件很多很乱,我们一步步来,先看点心,我们先求的点心能力为p的最小体积,再看看卡车在最小体积下的最小花费,于是就变成了两个先后问题,先对点心求多重背包,再对卡车求背包就行,这里的slove其实就是二进制枚举优化操作(为了防止超时,同时可以将多重背包转换成01背包)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=205;
const int N=5e4+100; 
const int inf=0x3f3f3f3f;
int dp[N],t[maxn],u[maxn],v[maxn],x[maxn],y[maxn],z[maxn],a[N],b[N],cnt=0;
void slove(int n,int s1[],int s2[],int s3[])
{
    cnt=0;
    for(int i=1;i<=n;++i)
    {
        int k=1;
        while(k<s3[i])
        {
            a[cnt]=k*s1[i],b[cnt++]=k*s2[i];
            s3[i]-=k;
            k*=2;
        }
        if(s3[i]) a[cnt]=s3[i]*s1[i],b[cnt++]=s3[i]*s2[i];
    }
}
int main()
{
    int T,n,m,p,sum1,sum2,ans,minn;
    scanf("%d",&T);
    while(T--)
    {
        sum1=sum2=0;ans=minn=inf;
        scanf("%d %d %d",&n,&m,&p);
        for(int i=1;i<=n;++i) scanf("%d %d %d",&t[i],&u[i],&v[i]),sum1+=t[i]*v[i];
        for(int i=1;i<=m;++i) scanf("%d %d %d",&x[i],&y[i],&z[i]),sum2+=x[i]*z[i];
        for(int i=0;i<N;++i) dp[i]=inf;
        dp[0]=0;
        slove(n,t,u,v);
        for(int i=0;i<cnt;++i)//dp[j]代表能量为j的最小体积 
        for(int j=p+100;j>=a[i];--j)//用滚动数组优化,所以逆序
        {
            dp[j]=min(dp[j],dp[j-a[i]]+b[i]);
            if(j>=p) minn=min(minn,dp[j]);
        }
        if(sum1<p||sum2<minn){
            printf("TAT\n");continue;
        }
        slove(m,x,y,z);
        for(int i=0;i<N;++i) dp[i]=0;
        for(int i=0;i<cnt;++i)//dp[j]代表花费为j的最大容积 
        for(int j=50000;j>=b[i];--j)
        {
            dp[j]=max(dp[j],dp[j-b[i]]+a[i]);
            if(dp[j]>=minn) ans=min(ans,j);
         } 
         if(ans>50000) printf("TAT\n");
         else printf("%d\n",ans);
    }
}
发布了391 篇原创文章 · 获赞 1 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105439852
今日推荐