Help Jimmy(DP)

题目链接:http://poj.org/problem?id=1661

题目
“Help Jimmy” 是在下图所示的场景上完成的游戏。

在这里插入图片描述

场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。

Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。

设计一个程序,计算Jimmy到底地面时可能的最早时间。

输入格式
第一行是测试数据的组数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恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。

输出格式
对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。

输入样例:

1
3 8 17 20
0 10 8
0 10 13
4 14 3

输出样例:

23
思路:

D P [ i ] [ 0 ] DP[i][0] DP[i][0] 表示第 i i i 个点最左端到最底的最短时间
D P [ i ] [ 1 ] DP[i][1] DP[i][1] 表示第 i i i 个点最右端到最底的最短时间
起始点可以看成 x = y x = y x=y 的板子,把全部板子按从高到低来排序
每个板子分别找一次
最左端到最底的最短时间

最右端到最底的最短时间

以最左端为例
假设当前是第 x x x 个板子,那么从第 x x x 个板子一直搜索到最后一个板子
只可能有两种情况
1 、 1、 1 这个板子底下有板子
2 、 2、 2 这个板子底下没有板子

情况 1 1 1 的处理办法:
分别求
当前板子的最左端到下面板子的最左端 + + + 下面板子最左端到最底的最短时间
d p [ i ] [ 0 ] + p l a t f o r m [ x ] . h − p l a t f o r m [ i ] . h + a b s ( p l a t f o r m [ x ] . x − p l a t f o r m [ i ] . x ) dp[i][0] + platform[x].h - platform[i].h + abs(platform[x].x - platform[i].x) dp[i][0]+platform[x].hplatform[i].h+abs(platform[x].xplatform[i].x)

当前板子到最左端到下面板子的最右端 + + + 下面板子最右端到最底的最短时

d p [ i ] [ 1 ] + p l a t f o r m [ x ] . h − p l a t f o r m [ i ] . h + a b s ( p l a t f o r m [ x ] . x − p l a t f o r m [ i ] . y ) dp[i][1] + platform[x].h - platform[i].h + abs(platform[x].x - platform[i].y) dp[i][1]+platform[x].hplatform[i].h+abs(platform[x].xplatform[i].y)
取最小值即是当前板子从最左端到最底的最短时间

如果在情况 1 1 1 中找到底下有板子做标记直接退出即可,否则进行情况 2 2 2 的处理

情况 2 2 2 的处理办法:
因为最左端底下没有板子,那么只要这个板子的高度小于等于MAX
那么就说明可以直接到最底,即
d p [ x ] [ 0 ] = p l a t f o r m [ x ] . h dp[x][0] = platform[x].h dp[x][0]=platform[x].h

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <climits>
#include <algorithm>

using namespace std;

const int N = 1010;

int T,n,x,h,m,ans;
int dp[N][2]; // 0表示左端到最底的时间,1表示右端到最底的时间
struct Node{

    int x;
    int y;
    int h;

}platform[N];


bool cmp(const Node &a,const Node &b)
{
    return a.h > b.h;

}

void left_min(int x)
{
    bool flag = false;
    for(int i = x+1; i <= n+1; i++)
    {
        if(platform[x].h - platform[i].h > m) // 高度太大
        {
            continue;
        }
        else if(platform[x].x >= platform[i].x && platform[x].x <= platform[i].y)
        {
            if(x == 59)
            {
                /*
                cout << "------------" << endl;
                cout << "x: " << x << endl;
                cout << "x.y: " << platform[x].y << endl;
                cout << "i: " << i << endl;
                cout << "i.x: " << platform[i].x << endl;
                cout << "i.y: " << platform[i].y << endl;
                cout << "------------" << endl;
                */
            }
            int a,b;
            a = dp[i][0] + platform[x].h - platform[i].h + abs(platform[x].x - platform[i].x); // 从下面左边走
            b = dp[i][1] + platform[x].h - platform[i].h + abs(platform[x].x - platform[i].y); // 从下面右边走
            dp[x][0] = min(a,b);
            flag = true;
        }


        if(flag) break;
    }
    if(!flag) // 左边底下没有板子
    {
        if(platform[x].h <= m) dp[x][0] = platform[x].h; // 可以到达
    }
}

void right_min(int x)
{
    bool flag = false;
    for(int i = x+1; i <= n+1; i++)
    {
        if(platform[x].h - platform[i].h > m) // 高度太大
        {
            continue;
        }
        else if(platform[x].y >= platform[i].x && platform[x].y <= platform[i].y)
        {
            int a,b;
            a = dp[i][0] + platform[x].h - platform[i].h + abs(platform[x].y - platform[i].x); // 从下面左边走
            b = dp[i][1] + platform[x].h - platform[i].h + abs(platform[x].y - platform[i].y); // 从下面右边走
            dp[x][1] = min(a,b);
            flag = true;
        }

        if(flag) break;
    }
    if(!flag) // 右边底下没有板子
    {
        if(platform[x].h <= m) dp[x][1] = platform[x].h; // 可以到达
    }
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&x,&h,&m);
        for(int i = 2; i <= n+1; i++) scanf("%d%d%d",&platform[i].x,&platform[i].y,&platform[i].h);
        platform[1].x = x;
        platform[1].y = x;
        platform[1].h = h;
        sort(platform+2,platform+2+n,cmp);
        memset(dp,0x3f,sizeof(dp));
        /*
        for(int i = 1; i <= n+1; i++)
        {
            cout << "i: " << i << " x: " << platform[i].x << endl;
            cout << "i: " << i << " y: " << platform[i].y << endl;
            cout << "i: " << i << " h: " << platform[i].h << endl;
        }
        cout << endl;
        */
        for(int i = n+1; i >= 1; i--)
        {
            left_min(i);
            right_min(i);
        }
        ans = min(dp[1][0],dp[1][1]);
        /*
        for(int i = 1; i <= n+1; i++)
        {
            cout << "i.x: " << " " << platform[i].x << endl;
            cout << "i.y: " << " " << platform[i].y << endl;
            cout << "i.h: " << " " << platform[i].h << endl;
            cout << "i: " << i << " left: " << dp[i][0] << endl;
            cout << "i: " << i << " right: " << dp[i][1] << endl;
        }
        */
        printf("%d\n",ans);

    }
    return 0;
}

Debug数据
输入

1
4 14 5 6
3 22 1
16 23 2
16 30 3
13 21 4

输出

15

输入

1
2 2 12 8
0 10 10
2 12 5

输出

22

输入

2
3 8 7 2
6 14 6
4 10 4
5 14 2
1 6 10 20
2 3 5

输出

17
10

输入

1
3 8 12 8
0 10 4
0 10 10
-2 4 6

输出

14

输入

1
10 899 52 50
893 903 18
890 900 38
898 908 8
910 920 8
894 904 43
881 891 18
872 882 38
867 877 43
842 852 43
895 905 3

输出

61

输入

4
3 4 4 5
3 5 3
1 7 2
2 6 1
3 8 17 20
0 10 8
0 10 13
4 14 3
3 4 4 5
3 5 3
1 4 2
2 6 1
3 4 4 5
3 6 3
5 7 2
1 4 1

输出

7
23
6
6

输入

1
3 8 17 20
8 10 8
8 10 13
8 14 3

输出

17

输入

1
60 822 302 50
813 823 298
813 823 293
816 826 213
816 826 178
817 827 218
813 823 148
821 831 73
814 824 248
813 823 283
815 825 158
819 829 58
814 824 13
813 823 28
819 829 233
814 824 43
773 783 293
821 831 93
818 828 268
816 826 198
818 828 113
814 824 208
816 826 68
821 831 133
794 804 248
814 824 108
829 839 28
818 828 143
844 854 298
802 812 133
801 811 28
818 828 238
817 827 8
816 826 48
820 830 3
819 829 288
822 832 138
820 830 183
855 865 13
777 787 268
820 830 63
789 799 28
822 832 33
855 865 213
779 789 208
836 846 248
806 816 33
821 831 263
818 828 83
846 856 263
789 799 68
854 864 8
854 864 283
801 811 298
805 815 143
822 832 23
821 831 173
813 823 153
858 868 138
818 828 98
839 849 133

输出

352
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值