题目
“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
思路
这道题一开始的时候其实我没太看懂输入,有点绕。
输入第一行的n,x,y,h分别对应有几个台阶,你当前处于的x位置,你当前处于的高度和你每次往下跳不能超过的高度。
首先我们在存储完所有的台阶之后,我们把自己所处的台阶(比较特别,x1=x2=x)和地面(也是比较特别,x1,x2都是无限大,h=0)也存在数组中。
struct node
{
int x1,x2,h;
} a[1100];
scanf("%d%d%d%d",&n,&x,&y,&maxh);
for(int i=1; i<=n; i++)
scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
a[n+1].x1=x;
a[n+1].x2=x;
a[n+1].h=y; //起点台阶的信息
a[0].x1=-2e6;
a[0].x2=2e6;
a[0].h=0; //地面的信息
然后我们将信息按高度从低到高排个序:
bool cmp(node b1,node b2)
{
return b1.h<b2.h;
}
sort(a,a+n+2,cmp); //一共有n+1个元素
接下来我们设计一个数组dp[1100][2]。
dp[i][0]的值为从第i层向左走到达地面的最短时间,dp[i][1]的值为从第i层向右走到达地面的最短时间。
接下来我们从第2层开始,算出每层向左走到达地面的最短时间和向右走的最短时间。
最后我们取dp[n+1][0]和dp[n+1][1]两者中较小值就ok了(贪心)。
直接看代码,伊丽莎白!
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int x1,x2,h;
} a[1100];
int n,x,y,maxh;
int dp[1100][2];
bool cmp(node b1,node b2)
{
return b1.h<b2.h;
}
void Leftmin(int m) //求第m层向左走到地面的最少时间
{
int k=m-1; //向下一层出发
while(k>0&&a[m].h-a[k].h<=maxh) //如果没到地面,并且允许我们跳下去
{
if(a[m].x1>=a[k].x1&&a[m].x1<=a[k].x2) //看一下能不能安全落地
{
dp[m][0]=a[m].h-a[k].h+min(a[m].x1-a[k].x1+dp[k][0],a[k].x2-a[m].x1+dp[k][1]); //落地之后选择向左还是向右继续走
return ;
}
else
k--;
}
if(a[m].h-a[k].h>maxh) //如果不可以直接跳到地面
dp[m][0]=2e6;
else //如果可以直接跳到地面
dp[m][0]=a[m].h; //信仰之跃
}
void Rightmin(int m) //求第m层向右走到地面的最少时间,一样的过程
{
int k=m-1;
while(k>0&&a[m].h-a[k].h<=maxh)
{
if(a[m].x2<=a[k].x2&&a[m].x2>=a[k].x1)
{
dp[m][1]=a[m].h-a[k].h+min(a[m].x2-a[k].x1+dp[k][0],a[k].x2-a[m].x2+dp[k][1]); //同样考虑向哪边走
return ;
}
else
k--;
}
if(a[m].h-a[k].h>maxh)
dp[m][1]=2e6;
else
dp[m][1]=a[m].h;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&n,&x,&y,&maxh);
for(int i=1; i<=n; i++)
scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
a[n+1].x1=x;
a[n+1].x2=x;
a[n+1].h=y;
a[0].x1=-2e6;
a[0].x2=2e6;
a[0].h=0;
sort(a,a+n+2,cmp);
for(int i=1; i<=n+1; i++)
{
Leftmin(i);
Rightmin(i);
}
cout<<min(dp[n+1][0],dp[n+1][1])<<endl; //最后贪一下(●'◡'●)
}
}
虽然只是蓝桥国三,但还是很开心o( ̄▽ ̄)ブ
继续努力,下次再见~