-
没考虑跳到下一个平台,但是会摔死情况,第二次编写时自然地发现了
-
如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所以坐标判断有没有落在平台上要加等号
-
对于情况2,可能有多个平台有端点重合,此时可以跳多个平台吗?实际上条件2隐含的意思是已经落在了最高的那个平台上,所以不用判断多个平台。也就是说,当我们按高度递减顺序找到第一个可以跳的平台,那么这个平台也是唯一可以跳的。
-
参考了别人的代码,将起点和地面也加入了平台数组。这样做统一了逻辑,简化了程序而且使得准确度提高。这种操作应当引起重视。
-
递推式:考虑从第i个平台落到第j个平台
如果从第i个平台的左边落下(求解LeftMinTime[i]),落到第j个平台后,
在第j个平台往左走:time1 = map[i].Lx - map[j].Lx + LeftMinTime[j]
在第j个平台往右走:time2 = map[j].Rx - map[i].Lx + RightMinTime[j];
综上:LeftMinTime = map[i].H - map[j].H + min(time1,time2); -
本题跟之前写过的递推很不一样的地方在于,由于人物从落到平台上的位置移动到左右两端也需要时间,而人物落到平台上的位置是随机的,所以不能将递推变量(或者说状态)定为——从某个平台落到地面的最短时间,因为这是不确定的,会随人物在平台上的位置而变的。而从某个平台的左端点/右端点落到地面的最短时间则不受人物在平台上的位置影响。
-
总结5:之前做到的递推是这样的:当维数为两维的Result数组,数组的每一个元素表示一个状态值。一般地,多维,但是只有一类状态值;本题目是这样的:有两个一维的数组,分别存放一类状态值。共两维,有两类状态值。
-
代码如下:
#include<iostream>
#include <cstring>
#include <algorithm>
using namespace std;
//如何处理INF情况——足够大的数字设置为INF
//二维数组排序——自己重写快速排序函数 or 结构体元素数组排序
const int MAXN = 1005;
const int MAXX = 20005;
const int INF=0x3f3f3f;
struct platform
{
int Lx,Rx,H;
}map[MAXN];
int cmp(platform c,platform b)
{
return c.H>b.H;//从大到小排列
}
int LeftMinTime[MAXN];
int RightMinTime[MAXN];
void Print(int N)
{
cout << "map" << endl;
for(int i=0;i<N+2;++i)
cout << map[i].Lx << " " << map[i].Rx << " " << map[i].H << endl;
cout << "arrayMinTime" << endl;
for(int i=0;i<N+2;++i)
cout << LeftMinTime[i] << " " << RightMinTime[i] << endl;
}
int main()
{
int t;
int N,X,Y,MAX;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&N,&X,&Y,&MAX);
//将地面和起点视作平台
map[0].Lx = -MAXX;
map[0].Rx = MAXX;
map[0].H = 0;
map[1].Lx = map[1].Rx = X;
map[1].H = Y;
for(int i=2;i<N+2;++i) //真正的平台索引:2~N+1 ,之后的元素可能是之前循环留下的,未作处理
scanf("%d%d%d",&map[i].Lx,&map[i].Rx,&map[i].H);
sort(map,map+N+2,cmp); //排序后起点一定在索引0,地面一定在索引N+1
memset(LeftMinTime,0,sizeof(LeftMinTime));
memset(RightMinTime,0,sizeof(RightMinTime));
//递推LeftMinTime、RightMinTime数组
//LeftMinTime[N+1] = RightMinTime[N+1] = 0;
for(int i=N;i>=0;--i)
{
int j=i+1;
//递推LeftMinTime数组
for(;j<N+1;++j) //仅看平台
{
// 只有跳下去不会死的平台才会进来这个if,能跳下去的平台足够近
if(map[i].Lx <= map[j].Rx && map[i].Lx >= map[j].Lx && map[i].H - map[j].H <= MAX)
{
//跳到第j个平台后 往左走
int tmp1 = map[i].Lx - map[j].Lx + LeftMinTime[j];
//跳到第j个平台后 往右走
int tmp2 = map[j].Rx - map[i].Lx + RightMinTime[j];
LeftMinTime[i] = map[i].H - map[j].H + min(tmp1,tmp2);
break; //找到第一个可以跳的平台
}
}
if(j == N+1) // 没有可跳的平台——能跳下去的平台太远或者是下面就是地面
{
if(map[i].H <= MAX) LeftMinTime[i] = map[i].H;
else LeftMinTime[i] = INF;
}
j = i+1;
for(;j<N+1;++j) //仅看平台
{
// 只有跳下去不会死的平台才会进来这个if,能跳下去的平台足够近
if(map[i].Rx <= map[j].Rx && map[i].Rx >= map[j].Lx && map[i].H - map[j].H <= MAX)
{
//跳到第j个平台后 往左走
int tmp1 = map[i].Rx - map[j].Lx + LeftMinTime[j];
//跳到第j个平台后 往右走
int tmp2 = map[j].Rx - map[i].Rx + RightMinTime[j];
RightMinTime[i] = map[i].H - map[j].H + min(tmp1,tmp2);
break; //找到第一个可以跳的平台
}
}
if(j == N+1) // 没有可跳的平台——能跳下去的平台太远或者是下面就是地面
{
if(map[i].H <= MAX) RightMinTime[i] = map[i].H;
else RightMinTime[i] = INF;
}
}
//Print(N);
cout << LeftMinTime[0] << endl;
}
return 0;
}