AC “Hello Jimmy” 的辛酸

  1. 没考虑跳到下一个平台,但是会摔死情况,第二次编写时自然地发现了

  2. 如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所以坐标判断有没有落在平台上要加等号

  3. 对于情况2,可能有多个平台有端点重合,此时可以跳多个平台吗?实际上条件2隐含的意思是已经落在了最高的那个平台上,所以不用判断多个平台。也就是说,当我们按高度递减顺序找到第一个可以跳的平台,那么这个平台也是唯一可以跳的。

  4. 参考了别人的代码,将起点和地面也加入了平台数组。这样做统一了逻辑,简化了程序而且使得准确度提高。这种操作应当引起重视。

  5. 递推式:考虑从第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);

  6. 本题跟之前写过的递推很不一样的地方在于,由于人物从落到平台上的位置移动到左右两端也需要时间,而人物落到平台上的位置是随机的,所以不能将递推变量(或者说状态)定为——从某个平台落到地面的最短时间,因为这是不确定的,会随人物在平台上的位置而变的。而从某个平台的左端点/右端点落到地面的最短时间则不受人物在平台上的位置影响。

  7. 总结5:之前做到的递推是这样的:当维数为两维的Result数组,数组的每一个元素表示一个状态值。一般地,多维,但是只有一类状态值;本题目是这样的:有两个一维的数组,分别存放一类状态值。共两维,有两类状态值。

  8. 代码如下:

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值