题目描述:
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。老鼠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
思路:
1.典型的动态规划的题目;
2.Jimmy到达一块板上时,可以有两个选择,向右或者向左,这两者之间一定有一个较小的值,因此要比较向左还是向右的时间更短。如果要给这两个数据加一个边界,可以选择以到达地面的时间为准,即:比较从这块板的左侧到达地面的时间和右侧到达地面的时间,比较出较小者;
3.于是,子问题可以分解为:从木板m左侧到达地面的时间,从木板m右侧到达地面的时间(两者写法类似)。
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
#define MAXTIME 60000
struct band{//分别为板的左侧,右侧和高度
int x1;
int x2;
int h;
};
int n,N,x,y,MAX;
band nband[1001];
int lefttime(band m);//从m的最左侧的点到地面所需时间
int righttime(band m);
int main()
{
cin>>n;
for(int i=0;i<n;i++){
cin>>N>>x>>y>>MAX;
for(int j=1;j<=N;j++){
cin>>nband[j].x1>>nband[j].x2>>nband[j].h;
}
for(int i=N-1;i>=1;i--){//把板从高到低排序
for(int j=1;j<=i;j++){
if(nband[j].h<nband[j+1].h){
band tmp=nband[j];
nband[j]=nband[j+1];
nband[j+1]=tmp;
}
}
}
nband[0].x1=x,nband[0].x2=x,nband[0].h=y;//把Jimmy的初始点放在0
cout<<righttime(nband[0])<<endl;
}
return 0;
}
int lefttime(band m)
{
int down=0;//首先寻找下方的板
for(int i=1;i<=N;i++){
if(nband[i].h<m.h&&m.x1>=nband[i].x1&&m.x1<=nband[i].x2){
down=i;
break;
}
}
if(down==0){//如果没找到,则下方是地面
if(m.h>MAX)return MAXTIME;
return m.h;
}
else{
int timedown=m.h-nband[down].h;//高度差
int ltime=lefttime(nband[down])+(m.x1-nband[down].x1);//递归+在板上移动的时间
int rtime=righttime(nband[down])+(nband[down].x2-m.x1);
timedown+=min(ltime,rtime);
return timedown;
}
return 0;
}
int righttime(band m)
{
int down=0;
for(int i=1;i<=N;i++){
if(nband[i].h<m.h&&m.x2>=nband[i].x1&&m.x2<=nband[i].x2){
down=i;
break;
}
}
if(down==0){
if(m.h>MAX)return MAXTIME;
return m.h;
}
else{
int timedown=m.h-nband[down].h;
int ltime=lefttime(nband[down])+(m.x2-nband[down].x1);
int rtime=righttime(nband[down])+(nband[down].x2-m.x2);
timedown+=min(ltime,rtime);
return timedown;
}
return 0;
}
细节处理:
1.新建一个数据结构来表示木板的性质;
2.木板数据输入后,要对木板进行从高到低的排序(很重要,因为下面寻找的时候是从高到低寻找);
3.Jimmy初始位置可以认为在一个没有长度的木板上;