【洛谷】P1156 垃圾陷阱(动态规划)

题目链接

题目描述

卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2≤D≤100)英尺。

卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间t(0<t≤1000),以及每个垃圾堆放的高度h(1≤h≤25)和吃进该垃圾能维持生命的时间f(1≤f≤30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续10小时的能量,如果卡门10小时内没有进食,卡门就将饿死。

输入输出格式

输入格式:

第一行为2个整数,D和 G(1≤G≤100),GG为被投入井的垃圾的数量。

第二到第G+1行每行包括3个整数:T(0<T<=1000),表示垃圾被投进井中的时间;F(1≤F≤30),表示该垃圾能维持卡门生命的时间;和 H(1≤H≤25),该垃圾能垫高的高度。

输出格式:

如果卡门可以爬出陷阱,输出一个整表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。

输入输出样例

输入样例#1: 复制

20 4
5 4 9
9 3 2
12 6 10
13 1 1

输出样例#1: 复制

13

说明

[样例说明]

卡门堆放她收到的第一个垃圾:height=9;

卡门吃掉她收到的第2个垃圾,使她的生命从10小时延伸到13小时;

卡门堆放第3个垃圾,height=19;

卡门堆放第4个垃圾,height=20。

背包气息很浓厚的题。

用dp[i][j]表示处理前i个垃圾后在高度为j时的最大生命值。将垃圾按扔下时间排序后,垃圾要么用来吃掉增加生命值,要么用来垫高。由此可以得到递推关系:

dp[i+1][j]=max(dp[i+1][j],dp[i][j]-(trash[i+1].t-trash[i].t)+trash[i+1].f);    //吃掉垃圾,不用来垫高 

dp[i+1][j+trash[i+1].h]=max(dp[i+1][j+trash[i+1].h],dp[i][j]-(trash[i+1].t-trash[i].t));//不吃垃圾,用来垫高

当然,有个前提条件是上一次的最大生命值能支撑到扔下这一次垃圾,这里还需要注意的是dp[i][j]=0时奶牛还没有死,还徘徊在生与死的边缘罢,因此dp数组初始化为-1。

当奶牛能爬出陷阱时,处理的最后一个垃圾一定是用来垫高的,满足生命值大于等于0且高度大于等于D时即可爬出陷阱,即:

dp[i+1][j+trash[i+1].h]>=0&&j+trash[i+1].h>=D

当奶牛不能爬出陷阱时,需要求最长的存活时间,那么显然奶牛把垃圾都用来吃不用来垫高可以使得存活时间越长。

AC代码:

#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
using namespace std;
struct node
{
	int t,h,f;
	friend bool operator < (node &a,node &b)
	{
		return a.t<b.t;
	}
	node()
	{
		t=0;h=0;f=0;
	}
}trash[101];
int main()
{
	int D,G,dp[101][101];//dp[i][j]为处理前i个垃圾(吃或不吃)后在高度为j时的最大生命值 
	cin>>D>>G;
	for(int i=1;i<=G;i++)
	    cin>>trash[i].t>>trash[i].f>>trash[i].h;
	memset(dp,-1,sizeof(dp));//初始化为-1 
	sort(trash+1,trash+G+1);//按扔下时间从小到大排序 
	
	bool flag=false;//能否爬出陷阱 
	int ans=0;//最长存活时间 
	dp[0][0]=10;//初始能量 
	for(int i=0;i<=G-1&&!flag;i++)
	{
		for(int j=0;j<=D&&!flag;j++)
		{
			if(dp[i][j]>=trash[i+1].t-trash[i].t)//上一次的能量足以支撑到下一个垃圾的来临 
			{
			//吃掉垃圾,不用来垫高 
                        dp[i+1][j]=max(dp[i+1][j],dp[i][j]-(trash[i+1].t-trash[i].t)+trash[i+1].f);
			//不吃垃圾,用来垫高 
			dp[i+1][j+trash[i+1].h]=max(dp[i+1][j+trash[i+1].h],dp[i][j]-(trash[i+1].t-trash[i].t));
			//能爬出陷阱的最后一步一定是不吃垃圾,用来垫高 
			if(dp[i+1][j+trash[i+1].h]>=0&&j+trash[i+1].h>=D)  
			{
				   cout<<trash[i+1].t<<endl;flag=true;//输出能爬出陷阱的最早时间 
			}
		        } 	
		}
		if(dp[i+1][0]>=0) ans=max(ans,dp[i+1][0]+trash[i+1].t);
	}

	if(!flag) cout<<ans;
	
}

猜你喜欢

转载自blog.csdn.net/qq_40889820/article/details/82117800