HDU 5445 Food Problem 两次多重背包

题目描述:

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

题目分析:
有一些cookie,每一种cookie都有其特定的energy,但也要占特定的volume,每一种cookie都有数量num。同时你拥有一些运载cookie的truck,每种truck也可以装载特定volume的cookie,每种truck需要特定的prize,每种truck也有特定数量num。
求将所有cookie都装载在truck中,求花费最小的prize,如果不能讲所有cookie装满,输出“TAT”。
因为在cookie装在truck是只计算volume值的,就是说可以将一种cookie分别装在不同的truck上。
要进行两次的多重背包,第一次对cookie的energy进行一次多重背包,找出最小的volume值。第二次对truck的prize进行一次多重背包,找出最小的volume值。这两次多重背包的结果根据volume值建立联系。最后再根据找一遍prize得出最终的答案。
(ps:这题需要进行二进制优化 不然要TLE)

代码如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

const int INF = 0x3f3f3f3f;
const int MAXN =65000;
using namespace std;

int dp[MAXN];//在第一次中,dp[i]表示在获得energy为i时最小的vol体积
             //在第二次中,dp[i]表示在花费prize为i时最小的vol体积
struct Cookie
{
    int val,vol,t;
}cookie[220];

struct Truck
{
    int vol,prize,t;
}truck[220];


int Mul_Pack1(Cookie cookie[], int n)//第一次多重背包
{
    memset(dp,INF,sizeof(dp));
    dp[0]=0;
    for(int i=1; i<=n; i++)//遍历每一种cookie
    {
        int t=cookie[i].t;
        for(int j=1; t>0; j<<=1)//寻找该种cookie选择次数
        {
            int tmp=min(t,j);//需要优化
            for(int k=60000; k>=cookie[i].val*tmp; k--)//对其energy进行dp
            {
                dp[k]=min(dp[k-cookie[i].val*tmp]+cookie[i].vol*tmp,dp[k]);
            }
            t-=tmp;
        }
    }
}

int Mul_Pack2(Truck truck[],int n)
{
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=n; i++)
    {
        int t=truck[i].t;
        for(int j=1; t>0; j<<=1)
        {//需要优化
            int tmp=min(t,j);
            for(int k=60000; k>=truck[i].prize*tmp; k--)
            {
                dp[k]=max(dp[k-truck[i].prize*tmp]+truck[i].vol*tmp,dp[k]);
            }
            t-=tmp;
        }
    }
}

int T;
int main()
{
    int n,m,p;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1; i<=n; i++)
           scanf("%d%d%d",&cookie[i].val,&cookie[i].vol,&cookie[i].t);
        for(int i=1; i<=m; i++)
           scanf("%d%d%d",&truck[i].vol,&truck[i].prize,&truck[i].t);
        Mul_Pack1(cookie,n);
        int minv=INF;//记录最小体积
        for(int i=p; i<=60000; i++)
        {
           minv=min(dp[i],minv);
        }
        if (minv==INF)
        {
            printf("TAT\n");
            continue;
        }
        Mul_Pack2(truck,m);
        bool f=false;
        int num;
        for(int i=1; i<=60000; i++)
        {
            if (dp[i]>=minv && dp[i]!=INF)
            {
                f=true;
                num=i;
                break;
            }
        }
        if (f) printf("%d\n",num);
        else printf("TAT\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值