首页 > 代码库 > 动规-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