题目地址:http://poj.org/problem?id=1661

Description

"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

Source

当Jimmy落在一个平台上后有两种选择(向左走或向右走),而Jimmy走到平台左边和右边的时间很容易计算,如果我们得到了以平台左边为起点及以平台右边为起点到地面的最短时间,那么选择往左走还是往右走就很容易了。这样,原问题就分解为两个子问题这两个子问题和原问题的形式是一致的了,也就找到了“状态”dp[i][j], j = 0, 1 (dp[i][0]表示以i号平台左边为起点到地面的最短时间,dp[i][1]]表示以i号平台右边为起点到地面的最短时间),而“状态转移方程”如下:

dp[i][0] = H[i] - H[m] + Min (dp[m][0] + X1[i] - X1[m], dp[m][1] + X2[m] - X1[i]);  m为i左边下面的平台的编号

dp[i][1] = H[i] - H[m] + Min (dp[m][0] + X2[i] - X1[m], dp[m][1] + X2[m] - X2[i]);  m为i右边下面的平台的编号

算法实现如下:

#include <stdio.h>
#include <stdlib.h> #define MAXN 1010
#define INF 9000000 typedef struct platform{
int x1;
int x2;
int high;
}Platform; int compare (const void * p, const void * q){
Platform * p1 = (Platform *)p;
Platform * q1 = (Platform *)q;
return p1->high - q1->high;
} int Min (int a, int b){
return (a < b) ? a : b;
} int N, X, Y, MAX;
Platform plat[MAXN];
int dp[MAXN][2]; //dp[i][0]、dp[i][1]分别表示从第i个平台左、右边到地面的最短时间 void LeftMinTime (int i){ //计算从平台i左边到地面的最短时间
int k = i - 1;
while (k > 0 && plat[i].high - plat[k].high <= MAX){
//如果平台i左边下面有平台,且两者相距不超过MAX
if (plat[i].x1 >= plat[k].x1 && plat[i].x1 <= plat[k].x2){
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
if (plat[i].high - plat[k].high > MAX)
dp[i][0] = INF;
else
dp[i][0] = plat[i].high;
} void RightMinTime (int i){ //计算从平台i右边到地面的最短时间
int k = i - 1;
while (k > 0 && plat[i].high - plat[k].high <= MAX){
//如果平台i右边下面有平台,且两者相距不超过MAX
if (plat[i].x2 >= plat[k].x1 && plat[i].x2 <= plat[k].x2){
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;
}
//如果平台i右边下面没有平台,或者两者相距超过了MAX
if (plat[i].high - plat[k].high > MAX)
dp[i][1] = INF;
else
dp[i][1] = plat[i].high;
} int ShortestTime (){
int i, j; for (i=1; i<=N+1; ++i){
LeftMinTime (i);
RightMinTime (i);
}
return Min (dp[N+1][0], dp[N+1][1]);
} int main(void){
int t;
int i;
while (scanf ("%d", &t) != EOF){
while (t-- != 0){
scanf ("%d%d%d%d", &N, &X, &Y, &MAX);
for (i=1; i<=N; ++i){
scanf ("%d%d%d", &plat[i].x1, &plat[i].x2, &plat[i].high);
}
plat[0].high = 0;
plat[0].x1 = -20000;
plat[0].x2 = 20000;
plat[N+1].high = Y;
plat[N+1].x1 = X;
plat[N+1].x2 = X;
//根据平台高度按从低到高排序
qsort (plat, N+2, sizeof(Platform), compare);
printf ("%d\n", ShortestTime());
}
} return 0;
}

参考资料:http://blog.csdn.net/alalalalalqp/article/details/9206299

POJ 1661 Help Jimmy -- 动态规划的更多相关文章

  1. POJ 1661 Help Jimmy(C)动态规划

    没刷过 POJ,这题是论坛有人问的,我才看看. 我发现 POJ 注册很奇怪,账号总是登不上去,弄的我还注册两个.Emmm 首次体验很差,还好我不在 POJ 刷题. 题目链接:POJ 1661 Help ...

  2. POJ 1661 Help Jimmy(递推DP)

    思路: 1. 每个板子有左右两端, dp[i][0], dp[i][1] 分别记录左右端到地面的时间 2. 从下到上递推计算, 上一层的板子必然会落到下面的某一层板子上, 或者地面上 总结: 1. 计 ...

  3. OpenJudge/Poj 1661 帮助 Jimmy

    1.链接地址: bailian.openjudge.cn/practice/1661 http://poj.org/problem?id=1661 2.题目: 总Time Limit: 1000ms ...

  4. POJ 1661 Help Jimmy(DP/最短路)

    Help Jimmy Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14980 Accepted: 4993 Descripti ...

  5. POJ 1661 Help Jimmy(二维DP)

    题目链接:http://poj.org/problem?id=1661 题目大意: 如图包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无限. Jimmy老鼠在时刻0从高于所有平台的 ...

  6. POJ - 1661 - Help Jimmy - 简单dp

    http://poj.org/problem?id=1661 一般化处理,把一开始的落地和大地都视作平台,设计平台类的属性.dp的时候显然是从上往下dp的,而且要小心Jimmy不能够穿过平台,也就是从 ...

  7. POJ 1661 Help Jimmy【DP】

    基础DP,过程想明白了其实也不复杂,从上面的推下面的比倒着推要简单很多.调试了半个多小时..简单dp依然不能快速AC..SAD.. 题目链接: http://poj.org/problem?id=16 ...

  8. POJ 1661 Help Jimmy LIS DP

    http://poj.org/problem?id=1661 对板按高度排序后. dp[i][0]表示现在站在第i块板上,向左跑了,的状态,记录下时间和其他信息. O(n^2)LIS: 唯一的麻烦就是 ...

  9. POJ 1661 Help Jimmy (dijkstra,最短路)

    刚在百度搜索了一下这道题的题解, 因为看到有别人用动态规划做的,所以想参考一下. 结果顺带发现了有那么几个网站,上面的文章竟然和我这篇一模一样(除了一些明显的错别字外),我去,作者还是同一个人Admi ...

随机推荐

  1. JSon实体类快速生成插件 GsonFormat 1.2.0

    写在前头:本插件只适用 android studio和 Intellij IDEA 工具,eclipse 的少年无视我吧!!! 这是一个根据JSONObject格式的字符串,自动生成实体类参数. gi ...

  2. 教你50招提升ASP.NET性能(十一):避免在调试模式下运行网站

    (17)Avoid running sites in debug mode 招数17: 避免在调试模式下运行网站 When it comes to ASP.NET, one of the most c ...

  3. 【55】让自己熟悉Boost

    1.网址:http://boost.org 2.有很多C++组织和网站,但是Boost库有两个优势:a.和标准委员会关系密切:b.加入C++标准的各种功能的测试场.

  4. android122 zhihuibeijing 主页面搭建

    右边主页面布局设计: 文字颜色选择器和是否点击的图片选择器  路径和写法: <?xml version="1.0" encoding="utf-8"?&g ...

  5. careercup-中等难度 17.8

    17.8 给定一个整数数组(有正数和负数),找出总和最大的连续序列,并返回总和. 解法: 就是求连续子序列的和最大,不过存在一个问题: 假设整个数组都是负数,怎么样才是正确的行为呢?看看这个简单的数组 ...

  6. 学习笔记之ulimit

    Linux对于每个用户,系统限制其最大进程数.为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数.可以用ulimit -a 来显示当前的各种用户进程限制. Linux/Unix ul ...

  7. Android进阶笔记04:Android进程间通讯(IPC)之Messenger

    一. Android进程间通讯之Messenger 的引入 (1)引言:      平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消 ...

  8. 学习jQuery后的部分总结

    1.remove和empty <div id="div1"> <ul id="ul1"> <li>嘿嘿</li> ...

  9. linux 软件安装各种方法

    一   简单介绍 1.软件安装卸载,分几种情况: A:RPM包 这种软件包就像windows的EXE安装文件一样,各种文件已经编译好,并打了包,哪个文件该放到哪个文件夹,都指定好了,安装非常方便,在图 ...

  10. iframe实现面页无刷新提交表单

    一.表单提交到了哪里? 这似乎是个无知的问题,我们都知道表单提交到服务器,java,php,asp等服务器,然后由服务器去读.那么之后呢,服务器总要返回点什么吧,要么返回 一个xml或json数据,要 ...