算法提高 A Careful Approach(暴力枚举 + 二分法 + 贪心法)

试题 算法提高 A Careful Approach

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  如果你认为参加一个编程比赛让你感到有压力,那么请你想象你是一个空中交通管制员。因为人命关天,所以一个空中交通管制员必须在时刻变化的环境中专注于任务,解决不可预知的事件。
  让我们将目光转向飞机的着陆流程。飞机进入目的地飞航情报区之后,就会报告自己的位置、方向和速度,然后管制员就需要制定计划让所有飞机按指令安全着陆。一般来说,连续的两次着陆之间间隔时间越长,就越安全。因为这些额外的时间能够让工程师有机会对天气变化以及其他突发事件作出反应。
  幸运的是,有一部分计划的制定可以自动化——这就是你来这里的原因。你会得到有关飞机着陆的脚本。每一个飞机都有一个安全着陆时间窗。你算出的指令必须要符合每个飞机的时间窗。另外,飞机的着陆时间点要尽量均匀,使得连续两次着陆的最小间隔尽量大。例如,如果三架飞机分别着陆于10:00am、10:05am、10:15am,那么最小间隔是五分钟,在头两架飞机之间。所有间隔不一定一样,但是最小的间隔要尽量大。
输入格式
  多组数据。每个数据第一行为一个整数n,为飞机架数。接下来n行,每行两个整数a[i],b[i]表示这架飞机只能在闭区间[a[i],b[i]]间降落。a[i]和b[i]的单位是分钟。输入的最后一行是一个零。
输出格式
  对于每组数据,先输出第几组,然后输出最小间隔,单位为分和秒,舍入到最近的整数。格式参见样例。
样例输入
3
0 10
5 15
10 15
2
0 10
10 20
0
样例输出
Case 1: 7:30
Case 2: 20:00
数据规模和约定
  20% n<=5
  100% 2<=n<=8, 0<=a[i], b[i]<=1440, 数据组数不大于20.


首先贴一个别人的链接,或许看过之后本文就不需要看了 ><
https://blog.csdn.net/howardemily/article/details/79509166
解题思路
暴力枚举:看到n<=8 ,不用太动脑子,可以把n架飞机的着陆次序全部枚举一遍,然后看看每种情况的最大的最小间隔,然后在这么多种着陆次序中取最大的间隔即可。
二分:在考虑每种方案时,利用二分法求得最大间隔,提高效率。
贪心:(记第一架飞机的左区间端点为a,间隔为b)让第一架着陆的飞机在其最早的时间着陆,然后如果 a+b 在第二架飞机的时间区间内,第二架飞机的着陆时间就为 a+b ,然后 同样地用 a+b+b 判断第三架飞机;如果第二架飞机的区间右端点(最晚着陆时间)小于 a+b,第二架飞机与第一架飞机降落的间隔肯定小于b,那么不符合要求,缩小降落时间再次求解;如果第二架飞机的区间左端点(最早降落时间)大于 a+b ,那么第二架飞机就在其左端点(记为c)降落,这种情况符合要求,不过此时要把时间更改为c,然后用 c+b 去判断第三架飞机。

next_permutation

  求全排列,可以全排列自定义类型。
  只不过要重写cmp函数
bool cmp(node a,node b){
	return a.id<b.id;
}
next_permutation(s+1,s+1+n,cmp)

AC代码如下
代码来自https://blog.csdn.net/qq_41856733/article/details/88535638 ,有改动

#include 
using namespace std;
const int maxn=10;//最多八架飞机

int n;		  //当前数据中有几架飞机
double ans;   //当前数据的最优解 
struct node{
	int L,R;//当前飞机降落的对应时间区间 
	int id;
}s[maxn];   //s[]记录当前对应飞机的降落区间 

bool cmp(node a,node b){
	return a.id<b.id;
}

int check(double mid)
{
	double x=s[1].L;//第一架降落飞机的最早降落点
	for(int i=2;i<=n;i++)//从第二架降落飞机开始判断 
	{
		x+=mid;//与上一架飞机间隔mid降落 
		if(x>s[i].R)//当前间隔超出当前飞机的降落区间(间隔太长了) 
			return 0;
		if(x<s[i].L)//当前间隔小于当前飞机降落区间(间隔太短了) 
			x=s[i].L;//直接让当前飞机在自己最早降落时间降落
		//两个if都判定失败,即在当前飞机区间内降落,继续判断下一架飞机 
	} 
	return 1; //所有飞机降落符合要求,当前间隔是可行解 
}
int main()
{
	int ccase=0;//记录当前是第几组数据
	while((cin>>n)&&n)//飞机数为0时退出
	{
		ccase++;
		for(int i=1;i<=n;i++)
		{
			cin>>s[i].L>>s[i].R;
			s[i].id=i;
		}
		ans=0;	//初始化ans
		do
		{
			double l=0,r=1440,mid;
			
			while(r-l>1e-6)//二分查找最优解 
			{
				mid=(l+r)/2;
				if(check(mid))//当前的间隔满足条件 
					l=mid;
				else//当前间隔太长 
					r=mid; 
			} 
			ans=max(ans,r);//维护符合要求最大区间 
		}while(next_permutation(s+1,s+1+n,cmp));//降落顺序进行全排列
		ans*=60;
		printf("Case %d: %d:%02d\n",ccase,(int)ans/60,(int)(fmod(ans,60)+0.5));
	} 
	return 0;
}

你可能感兴趣的:(蓝桥杯题库,题解,算法,c++,二分法,贪心算法)