POJ 1661 Help Jimmy(C)动态规划
没刷过 POJ,这题是论坛有人问的,我才看看。
我发现 POJ 注册很奇怪,账号总是登不上去,弄的我还注册两个。Emmm 首次体验很差,还好我不在 POJ 刷题。
题目链接:POJ 1661 Help Jimmy
解题思路
我最初想的是用递归从上往下不断选择方向,结果发现我有点傻了,这样极有可能 TLE。
其实应该是用动态规划解题。从下往上,将每块平台的左端点和右端点到地面的最短时间计算出来。最后得到人的最短时间。
思路详解:
很明显,平台有三个数据,左端点,右端点,高度。因此直接定义结构体如下:
typedef struct Node {
int left, right, height;
}Platform;// 平台
Platform plat[MAX_N];// 所有平台信息
这里有个细节就是将地面和人都看做平台。地面和人的数据如下:
// 地面,地面高度最小,故保存在数组第一个
plat[0].left = -20000;
plat[0].right = 20000;
plat[0].height = 0;
// 人,人高度最大,故保存在数组最后一个
plat[platNum - 1].left = plat[platNum - 1].right = x;
plat[platNum - 1].height = y;
升序排序。一如既往的使用 qsort 函数,自定义比较函数 compare。
从下往上遍历每个平台,分别计算左右端点的最短时间。保存在二维数组 time[MAX_N][2] 中。
计算数组的方法(以 time[i][0] 为例,i,j 表示平台):
遍历 i 下方的平台,找到一个人不会摔死的平台 j。(如果会摔死,说明 i 的端点 dir 是悬崖,退出 down 函数)
如果找到 j 位于 i 的下方。判断 j 是不是地面。
如果是地面,那么 i 的高度就是 i 的端点 dir 的最短时间。time[i][dir] = plat[i].height。
如果不是地面,那么 j 是平台(不包括地面),如下图所示:

补充:图中的 h 改为 th。
需要注意的是,time[j][0] 和 time[j][1] 本身可能就是悬崖。具体看代码的 if 条件判断。这种情况有其他处理方法,暂且不表。
如果都不是悬崖,那么状态转移方程为:time[i][dir] = MIN(time[j][0] + tl, time[j][1] + tr) + th;
th,tl,tr 这三个量很容易计算。不做说明。
因此最后的 time[i][0],其中 i 是人的下标,即为最终结果。
时间复杂度:main 函数里面有一个 for 循环,down() 里面有 for 循环。故为 O(n2)O(n^2)O(n2) 。
空间复杂度:结构体数组加上一个二维数组,总共不低于 O(n)O(n)O(n)。
C代码
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>// INT_MAX头文件
#define MAX_N 1003
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
typedef struct Node {
int left, right, height;
}Platform;// 平台
Platform plat[MAX_N];// 所有平台信息
int platNum;// 平台个数
int time[MAX_N][2];// 平台左端点和右端点到地面的最短时间
int maxHeight;// 每次下落的最大高度
int compare(const Platform* a, const Platform* b) {// 比较函数,平台高度升序
return (*a).height - (*b).height;
}
// 下落
// i 当前平台
// dir 下落后选择的方向,0表示左,1表示右
// x 平台i的端点横坐标,必须与dir对应
void down(int i, int dir, int x) {
// 查找i正下方的j
int j;
for (j = i - 1; j >= 0; --j) {
if (plat[i].height - plat[j].height > maxHeight) {// i和j的高度差超过最大值
time[i][dir] = INT_MAX;// 人会摔死,因此时间为正无穷,表示悬崖
return;
}
if (x >= plat[j].left && x <= plat[j].right) {// j在i正下方
break;// 已找到,退出循环
}
}
if (j == 0) {// j是地面
time[i][dir] = plat[i].height;// i的高度就是i的端点dir最短时间
return;
}
// j是平台(不包括地面),计算i的端点dir到地面的最短时间
int tl = x - plat[j].left;// i的端点到j的左端点的水平时间
int tr = plat[j].right - x;// i的端点到j的右端点的水平时间
int th = plat[i].height - plat[j].height;// i到j的垂直下落时间
if (time[j][0] == INT_MAX) {// j左边是悬崖
if (time[j][1] == INT_MAX) {// j右边是悬崖
time[i][dir] = INT_MAX;// 那么i的端点dir也是悬崖
} else {
time[i][dir] = time[j][1] + tr + th;// 走j的右边
}
} else {
if (time[j][1] == INT_MAX) {
time[i][dir] = time[j][0] + tl + th;// 走j的左边
} else {// j的左边和右边都不是悬崖,选择j的时间短的方向
time[i][dir] = MIN(time[j][0] + tl, time[j][1] + tr) + th;
}
}
}
int main() {
int t, n, x, y, max;
scanf("%d", &t);// 样例数
while (t--) {
scanf("%d %d %d %d", &n, &x, &y, &max);
maxHeight = max;// 每次下落的最大高度
platNum = n + 2;// 平台,人,地面。共n+2个“平台”
// 地面,地面高度最小,故保存在数组第一个
plat[0].left = -20000;
plat[0].right = 20000;
plat[0].height = 0;
// 人,人高度最大,故保存在数组最后一个
plat[platNum - 1].left = plat[platNum - 1].right = x;
plat[platNum - 1].height = y;
// 输入所有平台的左右端点坐标和高度
for (int i = 1; i < platNum - 1; ++i) {
scanf("%d %d %d", &plat[i].left, &plat[i].right, &plat[i].height);
}
qsort(plat, platNum, sizeof(Platform), compare);// 平台按照高度升序
time[0][0] = time[0][1] = 0;// 地面时间为0
for (int i = 1, j; i < platNum; ++i) {// 从下往上计算每个平台的最短用时
down(i, 0, plat[i].left);// 从i下落后走左边
down(i, 1, plat[i].right);// 从i下落后走右边
}
printf("%d\n", time[platNum - 1][0]);// 输出人到地面的最短用时
}
return 0;
}
提交结果

POJ 1661 Help Jimmy(C)动态规划的更多相关文章
- POJ 1661 Help Jimmy(递推DP)
思路: 1. 每个板子有左右两端, dp[i][0], dp[i][1] 分别记录左右端到地面的时间 2. 从下到上递推计算, 上一层的板子必然会落到下面的某一层板子上, 或者地面上 总结: 1. 计 ...
- POJ 1661 Help Jimmy -- 动态规划
题目地址:http://poj.org/problem?id=1661 Description "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度 ...
- OpenJudge/Poj 1661 帮助 Jimmy
1.链接地址: bailian.openjudge.cn/practice/1661 http://poj.org/problem?id=1661 2.题目: 总Time Limit: 1000ms ...
- POJ 1661 Help Jimmy(DP/最短路)
Help Jimmy Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14980 Accepted: 4993 Descripti ...
- POJ 1661 Help Jimmy(二维DP)
题目链接:http://poj.org/problem?id=1661 题目大意: 如图包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无限. Jimmy老鼠在时刻0从高于所有平台的 ...
- POJ - 1661 - Help Jimmy - 简单dp
http://poj.org/problem?id=1661 一般化处理,把一开始的落地和大地都视作平台,设计平台类的属性.dp的时候显然是从上往下dp的,而且要小心Jimmy不能够穿过平台,也就是从 ...
- POJ 1661 Help Jimmy【DP】
基础DP,过程想明白了其实也不复杂,从上面的推下面的比倒着推要简单很多.调试了半个多小时..简单dp依然不能快速AC..SAD.. 题目链接: http://poj.org/problem?id=16 ...
- POJ 1661 Help Jimmy LIS DP
http://poj.org/problem?id=1661 对板按高度排序后. dp[i][0]表示现在站在第i块板上,向左跑了,的状态,记录下时间和其他信息. O(n^2)LIS: 唯一的麻烦就是 ...
- POJ 1661 Help Jimmy (dijkstra,最短路)
刚在百度搜索了一下这道题的题解, 因为看到有别人用动态规划做的,所以想参考一下. 结果顺带发现了有那么几个网站,上面的文章竟然和我这篇一模一样(除了一些明显的错别字外),我去,作者还是同一个人Admi ...
随机推荐
- 17-ESP8266 SDK开发基础入门篇--TCP服务器 RTOS版,小试牛刀
https://www.cnblogs.com/yangfengwu/p/11105466.html 现在开始写... lwip即可以用socket 的API 也可以用 netconn 的API实 ...
- 用Python操作MySQL(pymysql)
用python来操作MySQL,首先需要安装PyMySQL库(pip install pymysql). 连接MySQL: import pymysql connect=pymysql.connect ...
- Hdu 5093 Battle Ship
每个海面要么放要么不放,因此可以用二分图匹配, 考虑把同一行内的能互相看到的点放到一个行块里,同一列内能看到的点放到一个列块里,然后每一个行块都可以和该行块里所有海面的列块连边,选了这个行块,就必须选 ...
- USACO 奶牛抗议 Generic Cow Protests
USACO 奶牛抗议 Generic Cow Protests Description 约翰家的N头奶牛聚集在一起,排成一列,正在进行一项抗议活动.第i头奶牛的理智度 为Ai,Ai可能是负数.约翰希望 ...
- Java后台读取excel表格返回至Web前端
如果是做连接数据库的话,系统难度就降低了不少:这次本人也算是体会到数据库的方便了吧(不过以后云储存好像会更受欢迎些):比如说查询列出所有数据吧:数据库每个表每一列都有列名,正常的做法是遍历数据库表,d ...
- vue中使用vue-pdf插件显示pdf
最近项目需求需要在vue中展示pdf,上网搜索了实现方法,找到vue-pdf这个插件非常好用,并且还有许多方法.属性能进行功能扩展. 一.安装 npm install --save vue-pdf 二 ...
- JavaScript中class类的介绍
class的概念 一.我们为什么要用到class类? 因为通过class类来创建对象,使得开发者不必写重复的代码,以达到代码复用的目的.它基于的逻辑是,两个或多个对象的结构功能类似,可以抽象出一个模板 ...
- Nginx服务器的安装
#解压之前下载的nginx源码安装包 [root@redhat7 nginx-1.8.1]# tar xzvf nginx-1.8.1.tar.gz #进到新解压出来的nginx目录下 [root@r ...
- [转]ProxmoxVE 干掉 VMware
很久没有写这种通俗易懂的文章了,不是我愤世嫉俗,而是因为确实太为那些花大价钱购买VMware的冤大头鸣不平. 确实VMware在虚拟化市场占有率非常高,技术也非常成熟,用户使用起来很方便,但是如果你是 ...
- 为什么printf()用%f输出double型,而scanf却用%lf呢?
转:https://blog.csdn.net/bat67/article/details/52056057 示例:double x:scanf(“%f”,&x):输入“123.4”,输出x的 ...