“Help Jimmy” 是在下图所示的场景上完成的游戏。
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
Input
第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1..N)。所有坐标的单位都是米。
Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Output
对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。
Sample Input
1
3 8 17 20
0 10 8
0 10 13
4 14 3
Sample Output
23
该题的目的是要求出jimmy从给定的XY到地面的最短时间,同样的转换到每一个平台上去的时候,要求出jimmy降落位置到左右最短的时间,进行记录,使用一个二维数组进行记录,具体操作步骤在代码中进行讲解;
AC代码:
//M - Help Jimmy POJ - 1661
#include <iostream>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define maxn 1010
#define INF 0x3f3f3f3f
///建立平台结构,便于存储
typedef struct platform
{
int x1, x2, high;
}Platform;
///方便后续的对平台进行高度的排序
int cmp(const void *p, const void *q)
{
Platform * p1 = (Platform *)p;
Platform * q1 = (Platform *)q;
return p1->high - q1->high;
}
///可以用STL中的min替代
int Min(int a, int b)
{
return (a < b) ? a : b;
}
int N, X, Y, MAX;
Platform plat[maxn];
int dp[maxn][2];///dp[x][0]代表向左走花费最少的时间, dp[x][1]则代表向右走所花费最少的时间
///计算向左走花费最少的时间
void LeftMinTime(int i)
{
int k = i - 1;///先从临近的下一层平台开始计算、
///保证k>0,以及两个相邻平台之间的高度差不大于MAX
while(k > 0 && plat[i].high - plat[k].high <= MAX)
{
///如果从i平台的左边落下去能够落到k平台上(条件保证)
if(plat[i].x1 >= plat[k].x1 && plat[i].x1 <= plat[k].x2)
{
///首先记录高度差,然后去比较从左边落下去朝那边走比较快(Min中比较的两个值为向左走所花费的时间以及向右走所花费的时间,不要忘记+k层向下或向右到达底部所花费最少的时间)
dp[i][0] = plat[i].high - plat[k].high + Min(plat[i].x1 - plat[k].x1 + dp[k][0], plat[k].x2 - plat[i].x1 + dp[k][1]);
///如果该层找到了最短那就返回结束这个函数
return ;
}
else --k;///否则查找下一层是否满足
}
///如果从i层到最底层的距离大于了MAX,也就不可能了,所以赋值为INF;
if(plat[i].high - plat[k].high > MAX)
dp[i][0] = INF;
else///否则时间为i层的高度
dp[i][0] = plat[i].high;
}
///同找左侧最短时间
void RightMinTime(int i)
{
int k = i - 1;
while(k > 0 && plat[i].high - plat[k].high <= MAX)
{
if(plat[i].x2 <= plat[k].x2 && plat[i].x2 >= plat[k].x1)
{
dp[i][1] = plat[i].high - plat[k].high + Min(plat[i].x2 - plat[k].x1 + dp[k][0], plat[k].x2 - plat[i].x2 + dp[k][1]);
return ;
}
else --k;
}
if(plat[i].high - plat[k].high > MAX)
dp[i][1] = INF;
else
dp[i][1] = plat[i].high;
}
int ShortestTime()
{
int i;
///从第一层开始向上跑,plat[0]会在main函数中初始化,为水平面;
for(i = 1; i <= N + 1; ++i)
{
LeftMinTime(i);
RightMinTime(i);
}
///N + 1为jimmy初始的位置,在main函数中初始化,返回最短的时间
return Min(dp[N+1][0], dp[N+1][1]);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d%d", &N, &X, &Y, &MAX);
for(int i = 1; i <= N; i++)
{
scanf("%d%d%d", &plat[i].x1, &plat[i].x2, &plat[i].high);
}
///底层的高度为0,且长度为无限长
plat[0].high = 0;
plat[0].x1 = -20000;
plat[0].x2 = 20000;
///jimmy初始的位置为XY,长度为0
plat[N + 1].high = Y;
plat[N + 1].x1 = X;
plat[N + 1].x2 = X;
///对所有的平台进行一个按照高度从小到大的排序,便于shortestTime()函数的运行
qsort(plat, N + 2, sizeof(Platform), cmp);
printf("%d\n", ShortestTime());
}
return 0;
}