Help Jimmy
-
总时间限制:
- 1000ms 内存限制:
- 65536kB
-
描述
-
"Help Jimmy" 是在下图所示的场景上完成的游戏:
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
输入
-
第一行是测试数据的组数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恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
输出
- 对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。 样例输入
-
1 3 8 17 20 0 10 8 0 10 13 4 14 3
样例输出
-
23
来源
- POJ Monthly--2004.05.15, CEOI 2000, POJ 1661, 程序设计实习2007
-
-
- 解题思路:很寻常的一个递归思路,我的方法是建立一个node结构体来记录平台信息,建立一个全局数组data<node>来存储所有平台,将老鼠的初始位置拟成一个平台存入第一个,经过由高度从高到低的排序,将参数代入递归中digui(int a,int b)a代表的是老鼠跳到了那个平台,b代表的是老鼠在这个平台上往的左右那边走,这样就能知道老鼠的下一跳的位置,循环平台数组data找出符合条件的下一个平台,累加下落时间及到左右端的时间及左右端的下一跳的时间和,比较大小返回小的,如果勋魂没有下一跳,设置边界条件。
-
- 踩中的坑:我开始的递归参数传入的是层数和老鼠直接的位置,但是这样做数据太大,如果不做备忘录会超时,而做了备忘录会因为所要构建空间太大也会超时。所以我第二个参数改为了用一个值来判断老鼠是向左还是向右再根据平台信息得出位置代替直接位置信息。
-
- 代码如下:
-
#include <iostream> #include <vector> #include <algorithm> #include <math.h> using namespace std; struct node{ int X1; int X2; int H1; }; int digui(int a,int b); //利用递归思想解出问题 bool cmp(node a,node b);//给出的平台排序的标准,让给出的平台高度从高到低 int N,X,Y,Max; vector<node> data;//记录平台信息 vector<vector<int> > judge;//递归备忘录 int main(){ int t; int i = 0,j = 0; cin>>t; while(t--){ cin>>N>>X>>Y>>Max; X += 20000; data.resize(N+1);//N个平台,第零个是给的初始位置 data[0].X1 = X; data[0].X2 = X; data[0].H1 = Y; for(i = 1;i<N+1;i++){ cin>>data[i].X1; cin>>data[i].X2; cin>>data[i].H1; data[i].X1 += 20000; data[i].X2 += 20000; } judge.resize(N+2); for(i=0;i<N+2;i++){ judge[i].resize(2,-1); } //排序后,因为平台高度从高到低的 //当老鼠处于一个点时那么它就只有一个对应能跳到的平台或者只能直接跳地 sort(data.begin(),data.end(),cmp); cout<<digui(0,0)<<endl; data.clear(); for(i = 0;i<N+2;i++){ judge[i].clear(); } judge.clear(); } return 0; } //a代表处于第几层平台,b只有两个值0/1d代表了向左还是向右走 //利用递归思想:从第零层老鼠初始位置开始,根据层数及给出的位置 //判断往那边走更近,层层递推,得出答案。 int digui(int a,int b){ if(judge[a][b] != -1){ return judge[a][b]; } int temp = 0 ;//记录老鼠在此平台在那边那个位置 if(b == 0){ temp = data[a].X1; }else{ temp = data[a].X2; } int left = 9999999; int right = 9999999; for(int i = a+1;i<N+1;i++){//因为平台数组高度有序,所以不用从头计算 if(data[i].X1 <= temp && data[i].X2 >= temp){ if(data[a].H1 - data[i].H1 <= Max){//如果能跳到下一层 left = data[a].H1 - data[i].H1 + temp - data[i].X1 + digui(i,0); //下一层向左走的时间 right = data[a].H1 - data[i].H1 + data[i].X2 - temp + digui(i,1); //下一层向右走的时间 return judge[a][b] = left<right?left:right;//返回小的时间 } } } if(data[a].H1 <= Max)//如果循环中没找到,说明没有平台能让老鼠跳,那么要么此路不通,那么能直接到地 return data[a].H1; return 9999999; } bool cmp(node a,node b){ return a.H1>b.H1; }