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

解题思路:

  离散化处理 + DP。

  首先,纵坐标除了用来判断老鼠是否会摔死之外基本没用,主要考虑横坐标,只要求出在横坐标上必须走的最短距离,加上题目给出的Y就是答案了。由题目知-20000 <= X, X1[i], X2[i] <= 20000,为了方便后面的处理,我们把这三个数据统一加上20000,不让他出现负数。

  接下来介绍DP的思路,dp[i][x]——代表走到第 i 个平台的横坐标为 x 的点所需走过的最短距离(这里的距离其实都只是考虑横坐标上的距离,不考虑纵坐标,下面的讨论也一样),但是 1 <= N <= 1000 和 x 数据范围显然不允许我们开出这么大的数组,因此我们可以用离散化的技巧,把 x 的数据范围缩小为 [0,2000],这样就勉强可以开出数组了。我们先把平台按照高度由高到低的顺序排好序,则 dp[i][x] = min(dp[i][x] , dp[j][第 j 个平台的左端点坐标](条件:老鼠从第  j 个平台掉到第 i 个平台不会掉死并且这两点之间没有其他平台,右端点一样), dp[j][第 j 个平台的右端点坐标])(j 是从老鼠掉下来的第一个平板到第 i 个平板之间的所有平板)。

  具体细节请看代码。

AC代码:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=+,inf=0x7ffffff;
struct node{
int x1,x2,h;
}plat[maxn];
bool cmp(node &a, node &b){
return a.h>b.h;
}
int dp[maxn][maxn<<];
int xs[maxn<<],x_on[];
int vis[maxn][]; //0,左端点;1,右端点。这个vis数组是重点,标记第i个平台的左右端点是否已经处理过了
int main(){
int t,X,Y,N,MAX;
scanf("%d",&t);
while(t--){
memset(vis,,sizeof(vis));
memset(x_on,-,sizeof(x_on));
scanf("%d%d%d%d",&N,&X,&Y,&MAX);
X+=; //记得X也要加20000
int x_num=;
for(int i=;i<N;i++){
scanf("%d%d%d",&plat[i].x1,&plat[i].x2,&plat[i].h);
plat[i].x1+=, plat[i].x2+=; //离散化
//*******************************************************************
if(x_on[plat[i].x1]==-){
x_on[plat[i].x1]=x_num; xs[x_num++]=plat[i].x1;
}
if(x_on[plat[i].x2]==-){
x_on[plat[i].x2]=x_num; xs[x_num++]=plat[i].x2;
}
}
sort(xs,xs+x_num);
for(int i=;i<x_num;i++)
x_on[xs[i]]=i;
//******************************************************************** int newx;
sort(plat,plat+N,cmp); int start;
for(start=;start<N;start++){
if(plat[start].x1<=X&&plat[start].x2>=X)
break;
vis[start][]=vis[start][]=;
} //找出老鼠落下的第一个平台,上面的平台不会再用到了,我们随手处理一下访问标记 if(start==N){ //老鼠直接掉到地上的情况也不能忘了考虑哦
printf("%d\n",Y);
continue;
} for(int i=;i<N;i++){
for(int j=;j<x_num;j++) dp[i][j]=inf;
}
newx=x_on[plat[start].x1];
dp[start][newx]=X-plat[start].x1;
newx=x_on[plat[start].x2];
dp[start][newx]=plat[start].x2-X;
for(int i=start+;i<N;i++){
int l=plat[i].x1,r=plat[i].x2,h=plat[i].h;
for(int j=start;j<i;j++){
//如果第j个平台的端点已经被访问了,即对应的vis数组为1,就说明在这个端点到第i个平台之间有平台阻挡
if(vis[j][]&&vis[j][]) continue;
if(plat[j].h-h>MAX) continue; if(!vis[j][]&&plat[j].x1<=r&&plat[j].x1>=l){
vis[j][]=;
dp[i][x_on[l]]=min(dp[i][x_on[l]],dp[j][x_on[plat[j].x1]]+plat[j].x1-l);
dp[i][x_on[r]]=min(dp[i][x_on[r]],dp[j][x_on[plat[j].x1]]+r-plat[j].x1);
}
if(!vis[j][]&&plat[j].x2<=r&&plat[j].x2>=l){
vis[j][]=;
dp[i][x_on[l]]=min(dp[i][x_on[l]],dp[j][x_on[plat[j].x2]]+plat[j].x2-l);
dp[i][x_on[r]]=min(dp[i][x_on[r]],dp[j][x_on[plat[j].x2]]+r-plat[j].x2);
}
}
}
int ans=inf;
for(int i=N-;i>=start;i--){
//从最后一个平台往前遍历,凡是vis标记为0的,即证明这一点没有被处理过,也就证明这一点到地面之间没有阻挡,那么可以从这一点直接跳到地面
if(plat[i].h>MAX) break; //遍历到高度大于MAX的平台就结束
if(!vis[i][])
ans=min(ans,dp[i][x_on[plat[i].x1]]);
if(!vis[i][])
ans=min(ans,dp[i][x_on[plat[i].x2]]);
}
printf("%d\n",ans+Y);
}
return ;
}

POJ1661的更多相关文章

  1. POJ1661 Help Jimmy

    Help Jimmy Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9863 Accepted: 3201 Descriptio ...

  2. Help Jimmy ~poj-1661 基础DP

    Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无限. Jimmy老鼠在时刻0从高于所有平台的某处开始下落, ...

  3. POJ1661(KB12-M DP)

    Help Jimmy Description "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无 ...

  4. poj1661 (DP)

    题目链接:http://poj.org/problem?id=1661 思路: 把初始位置看成左,右端点均为x0,即长度为0,高度为y0的一个平台,按照平台高度从低到高排序.用dp[i][0],dp[ ...

  5. 【动态规划】POJ1661 Help Jimmy

    Help Jimmy Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11621   Accepted: 3827 Descr ...

  6. kuangbin专题十二 POJ1661 Help Jimmy (dp)

    Help Jimmy Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14214   Accepted: 4729 Descr ...

  7. poj1661【DP,左右两端dp】

    /* [过滤这一段~~~] 一开始想的[错误的,为自己的总结的写的,读者略过]: 每个状态的点肯定是高度,那么我DP每一层,这样的话就有一层循环,其实这无关复杂度,不会很多时间 错误的是想法是从最高层 ...

  8. POJ1661 Help Jimmy —— DP

    题目链接:http://poj.org/problem?id=1661 Help Jimmy Time Limit: 1000MS   Memory Limit: 10000K Total Submi ...

  9. [kuangbin带你飞]专题十二 基础DP1

            ID Origin Title   167 / 465 Problem A HDU 1024 Max Sum Plus Plus   234 / 372 Problem B HDU 1 ...

随机推荐

  1. 谁需要GUI?快看Linux 终端生存之道

    完全在 Linux 终端中生存并不容易,但这绝对是可行的. 处理常见功能的最佳 Linux shell 应用 你是否曾想像过完完全全在 Linux 终端里生存?没有图形桌面,没有现代的 GUI 软件, ...

  2. c/c++头文件的摘抄

    C/C++常用头文件 以及简单应用介绍 C/C++头文件一览 C #include <assert.h> //设定插入点 #include <ctype.h> //字符处理 # ...

  3. python(random 模块)

     一.Random 模块 注意:random() 是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法. 1.random.random() 返回随机生成的一个 ...

  4. RF(表格数据获取)

    一.表格数据获取 Get Table Cell [locator | row | col] 获取表格数据 Open Browser file:///D:/HBuilderX/workspace/Pro ...

  5. MySQL 8.0.20 源码安装数据库软件

    官方支持的平台: https://www.mysql.com/support/supportedplatforms/database.html

  6. java的++i和i++的分析

    关于自增自减,先来一道题,大家尝试着做一下: public static void main(String[] args) { int a=2; int b=a++; int c=--a; Syste ...

  7. Java——IO流超详细总结

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 在初学Java时,I ...

  8. P1714切蛋糕(不定区间最值)

    题面 今天是小Z的生日,同学们为他带来了一块蛋糕.这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值. 小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又 ...

  9. 数位dp H - F(x) HDU - 4734

    http://acm.hdu.edu.cn/showproblem.php?pid=4734 一般数位dp表示的是数的性质,这个题目也是一样,但是我们求出来的是一个函数的值,怎么把这个值转化成一类数, ...

  10. 推荐算法_CIKM-2019-AnalytiCup 冠军源码解读

    最近在帮一初创app写推荐系统,顺便学习一波用户兴趣高速检索的冠军算法. 写总结前贴出冠军代码的git地址:https://github.com/ChuanyuXue/CIKM-2019-Analyt ...