M - Help Jimmy POJ - 1661【动态规划】

“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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值