题目大意:
有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);
}
}