程序设计与算法(二)算法基础7.1Help 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

思路:

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初始位置可以认为在一个没有长度的木板上;

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值