首页 > 代码库 > 动规-POJ-1661

动规-POJ-1661

http://poj.org/problem?id=1661

Help Jimmy

在同一竖直平面上,存在地面(高度为0,长度无限),以及若干个给定高度的水平平台(高度、左右端点给定)。

现有Jimmy从给定点(x, y)跳下,下落的速度恒为1单位距离/单位时间。但下落的距离不能超过给定的高度MAX,否则Jimmy就会摔死。

若Jimmy降落在某一个平台上,那么Jimmy可以选择从平台的左端点或者右端点继续跳下。

问:Jimmy到达地面的最短时间。

保证Jimmy一定有办法安全降落到地面。

保证没有重叠的平台。

若Jimmy恰好落在平台的左端点或者右端点,也算作Jimmy跳到这个平台上。

解题报告

思路

首先,可以把题设中的其实点和地面也抽象为平台加入平台数组中。

每个平台都有从左跳和从右跳两种选择,且跳之后的落点是确定的,跳之前的状态不影响跳之后的状态转移,没有后效性——动态规划。

首先将平台数组按高度排序。

随后建立数组dp[i][j]表示,Jimmy达到第i个平台的j端点时,需要的最短时间。

初始化dp[0][0] = dp[0][1] = 1(初始点时间花费为0)

从高到低遍历每个平台,枚举从平台左右端点跳下的情况.

假设从i平台的j端点跳下以后,能安全到达k平台,那么:

dp[k][0] = min(dp[k][0], dp[i][j] + 高度差 + 从k平台上的落点到0端点的时间花费)

dp[k][1] = min(dp[k][1], dp[i][j] + 高度差 + 从k平台上的落点到1端点的时间花费)

要注意,下落过程不能穿过平台,所以每个平台跳下过程最多从左右端点各转移一次。

当然,到达地面以后不需要跑到左右端点,所以要特判一下到达地面的情况。

最后输出min( dp[地面][0], dp[地面][1] )即可

代码

#include <algorithm>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 1003;
const int INF = 20004;

struct Platform {
    int l, r, h;
    Platform(int _l = 0, int _r = 0, int _h = 0) : l(_l), r(_r), h(_h) {}
    bool operator<(const Platform &Right) const {
        return h > Right.h;
    }
} platform[maxn];

int n, t, cnt;
int stx, sty, maxh;
int top;

int dp[maxn][2];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> t;
    while (t--) {
        cin >> n >> stx >> sty >> maxh;
        cnt = 0;
        for (int i = 0; i < n; i++) {
            int l, r, h;
            cin >> l >> r >> h;
            if (h > sty || (h == sty && (stx < l || stx > r))) continue;
            platform[cnt++] = Platform(l, r, h);
        }
        platform[cnt++] = Platform(stx, stx, sty);
        platform[cnt++] = Platform(-INF, INF, 0);
        sort(platform, platform + cnt);
        memset(dp, 0x3f3f3f3f, sizeof(dp));
        dp[0][0] = dp[0][1] = 0;
        for (int i = 0; i < cnt - 1; i++) {
            bool flagl = false, flagr = false;
            for (int j = i + 1; j < cnt && platform[i].h - platform[j].h <= maxh; j++) {
                if(flagl && flagr) break;
                if (platform[i].l >= platform[j].l && platform[i].l <= platform[j].r && !flagl) {
                    dp[j][0] = min(dp[j][0], dp[i][0] + platform[i].h - platform[j].h + platform[i].l - platform[j].l);
                    dp[j][1] = min(dp[j][1], dp[i][0] + platform[i].h - platform[j].h + platform[j].r - platform[i].l);
                    if (j == cnt - 1) {
                        dp[j][0] = min(dp[j][0], dp[i][0] + platform[i].h - platform[j].h);
                        dp[j][1] = min(dp[j][1], dp[i][0] + platform[i].h - platform[j].h);
                    }
                    flagl = true;
                }
                if (platform[i].r >= platform[j].l && platform[i].r <= platform[j].r && !flagr) {
                    dp[j][0] = min(dp[j][0], dp[i][1] + platform[i].h - platform[j].h + platform[i].r - platform[j].l);
                    dp[j][1] = min(dp[j][1], dp[i][1] + platform[i].h - platform[j].h + platform[j].r - platform[i].r);
                    if (j == cnt - 1) {
                        dp[j][0] = min(dp[j][0], dp[i][1] + platform[i].h - platform[j].h);
                        dp[j][1] = min(dp[j][1], dp[i][1] + platform[i].h - platform[j].h);
                    }
                    flagr = true;
                }
            }
        }
        cout << min(dp[cnt - 1][0], dp[cnt - 1][1]) << endl;
    }
    return 0;
}

--(完)-- 

动规-POJ-1661