POJ 1661 Help Jimmy (dp)

题目大意:

有n个平台,左端点为x1,右端点为x2,高为h。从x处,高y米跳下,每秒移动1米,一次下降不能超过MAX米,问最快何时到达地面。

思路:

到达每个平台左右端点的最快时间只由比它高的平台绝对,满足dp的性质,可以用dp解决。

dpl[i]到达第i个平台左端点最快时间

dpr[i]到达第i个平台右端点最快时间

第i个平台左端点

dpl[i] = min( dpl[i], dpl[j] + h[j] - h[i] + x1[j] - x1[i])  // 第j个平台左端点下落能到第i个平台上

dpl[i] = min( dpl[i], dpr[j] + h[j] - h[i] + x2[j] - x1[i]) // 第j个平台右端点下落能到第i个平台上

第i个平台右端点

dpr[i] = min( dpr[i], dpl[j] + h[j] - h[i] + x2[i] - x1[j])

dpr[i] = min( dpr[i], dpr[j] + h[j] - h[i] + x2[i] - x2[j])

要特别注意判断从前面的平台下来会不会落到当前平台上,所以要记录上面平台的位置判断是否挡住更上面的平台

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2010;
const int inf = 0x7fffffff;
int dpl[maxn],dpr[maxn];
bool vis[40010];
int n,x,y,maxh;
struct node{
	int x1,x2,h;
};
node a[maxn];
bool cmp(node a, node b)
{
	return a.h > b.h;
}
int main()
{

	int t; scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d",&n,&x,&y,&maxh);
		memset(a,0,sizeof(a));
		memset(dpl,0x33,sizeof(dpl));
		memset(dpr,0x33,sizeof(dpr));
		
		for(int i = 0 ; i < n; i++)
		{
			scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
		}
		a[n].x1 = x;
		a[n].x2 = x;
		a[n].h = y;
		sort(a,a + n + 1, cmp);	
		dpl[0] = 0; dpr[0] = 0;
		for(int i = 0; i <= n; i++)
		{
			memset(vis,0,sizeof(vis));
			memset(&vis[a[i].x1 + 20000], 1, a[i].x2 - a[i].x1 + 1);
			for(int j = 1; j <= i; j++)
			{
				if(a[i - j].h - a[i].h <= maxh)
				{
					int temp = a[i - j].h - a[i].h;
					if(vis[a[i - j].x1 + 20000])	//i - j左端掉下来能落到i上 
					{						
						dpl[i] = min(dpl[i], dpl[i - j] + temp + a[i - j].x1 - a[i].x1);
						dpr[i] = min(dpr[i], dpl[i - j] + temp + a[i].x2 - a[i - j].x1);
					}
					if(vis[a[i - j].x2 + 20000])	//i - j右端掉下来能落到i上 
					{
						dpl[i] = min(dpl[i], dpr[i - j] + temp + a[i - j].x2 - a[i].x1);
						dpr[i] = min(dpr[i], dpr[i - j] + temp + a[i].x2 - a[i - j].x2);
					}
					if(a[i - j].x2 > a[i - j].x1)
						memset(&vis[a[i - j].x1 + 20001], 0, a[i - j].x2 - a[i - j].x1 - 1);
				}
				else break;
			}
			
		}
		int ans = inf;
		memset(vis,1,sizeof(vis));
		for(int i = n; i >= 0; i--)
		{
			if(a[i].h <= maxh)
			{
				if(vis[a[i].x1 + 20000])
				{
					ans = min(ans, dpl[i] + a[i].h);
				}
				if(vis[a[i].x2 + 20000])
				{
					ans = min(ans, dpr[i] + a[i].h);
				}
				if(a[i].x2 > a[i].x1)
					memset(&vis[a[i].x1 + 20001], 0, a[i].x2 - a[i].x1 - 1);
			}
			else break;
		}
		printf("%d\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值