HDU 5445 Food Problem(多重背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5445

参考来源:http://blog.csdn.net/mr_xujh/article/details/48435527

题面:

Food Problem

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 299    Accepted Submission(s): 106


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(T10) representing the number of test cases.

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

The ith of the n following lines contains three integers ti,ui,vi(1ti100,1ui100,1vi100) indicating that the ith 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(1xj100,1yj100,1zj100) indicating that the jth 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


解题:

    核心部分就是一个多重背包,通过将物品合并,极大地降低了复杂度,实现了优化。不过这道题转了两个弯,先要求出达到或大于能量需求的最小体积,再求出达到或大于最小体积的最小花费。虽然不是很难,但转了两个弯,让我自己写,目前是不大可能写出来的,代码是完全依瓢画葫芦按这位Mr_Xujh的代码写的,加了些注释。


代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct dessert
{
	int energy,space;
	void add(int x,int y)
	{
		energy=x,space=y;
	}
}store[2000];
//2000是因为最多200种甜点,而每种甜点数量不超过100,拆分成2的倍数,10个肯定够了
struct truck
{
	int size,cost;
	void add(int x,int y)
	{
		size=x;
		cost=y;
	}
}info[2000];
//2000同上
int min(int a,int b)
{
	return a<b?a:b;
}
int max(int a,int b)
{
	return a>b?a:b;
}
int minv,minc;//满足能量大于等于p的最小体积,满足体积大于等于minv的最小花费
int dp1[50105],dp2[50010];
//dp1[x]能量为x时的最小体积,dp2[x]花费为x时的最大体积
int main()
{
	int cas,n,m,p,t,u,v,k,x,y,z,cnt1,cnt2;
	scanf("%d",&cas);
	while(cas--)
	{
      scanf("%d%d%d",&n,&m,&p);
	  //初始化
	  cnt1=cnt2=0;//俩下标
	  memset(dp1,0x3f,sizeof(int)*(p+101));
	  memset(dp2,0,sizeof(int)*(50010));
	  minv=1e9;
	  minc=1e9;
      for(int i=1;i<=n;i++)
	  {
		  scanf("%d%d%d",&t,&u,&v);
          k=1;
		  //多重背包的核心部分,将同种物品以特定规则合成新的物品,降低复杂度
		  while(k<v)
		  {
			  store[cnt1++].add(k*t,k*u);
			  v-=k;
			  //分别为1,2,4...任何数量皆可由这些数量拼接而成
			  k<<=1;
		  } 
		  //仍有剩余,再装新形成一个物品
		  if(v)
		    store[cnt1++].add(v*t,v*u);
      }
	  dp1[0]=0;
	  //遍历新形成的物品
	  for(int i=0;i<cnt1;i++)
		  //p+100是因为一个物品最多产生100的能量差异
		  for(int j=p+100;j>=store[i].energy;j--)
		  {
			  //当前达到当前能量体积最小值等于当前值和选择这个物品的最小值
			  dp1[j]=min(dp1[j],dp1[j-store[i].energy]+store[i].space);
			  //如果当前能量大于等于p,且体积更小则更新
			  if(j>=p&&dp1[j]<minv)
				 minv=dp1[j];
		  }
	  for(int i=1;i<=m;i++)
	  {
		  scanf("%d%d%d",&x,&y,&z);
		  k=1;
		  //同上,重组物品
		  while(k<z)
		  {
			  info[cnt2++].add(k*x,k*y);
			  z-=k;
			  k<<=1;
		  }
		  if(z)
			  info[cnt2++].add(z*x,z*y);
	  }
      for(int i=0;i<cnt2;i++)
		  for(int j=50000;j>=info[i].cost;j--)
		  {
             //使用j花费所能达到的最大体积
             dp2[j]=max(dp2[j],dp2[j-info[i].cost]+info[i].size);
			 //如果当前花费下体积大于等于最小需求体积,且花费小于最小花费,则更新
			 if(dp2[j]>=minv&&j<minc)
				 minc=j;
		  }
	  //如果最小花费大于50000,输出TAT,否则输出最小值
	  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、付费专栏及课程。

余额充值