蓝桥杯--飞机降落

关键分析

1.原想法:这不妥妥贪心吗,直接排序,遍历,over

结果...先按最晚开始时间排序(会议问题),只通过了两个案例,上acwing测试,得到一组wa案例,然后再尝试按最早开始时间排序,更少了,只过了一个

此题不能用贪心,因为无法确定顺序

2.观察数据范围:N<=10,无脑暴搜dfs

3.分析dfs()怎么写

(1)参数:应该有两个,第一个x表示搜索了几辆飞机,第二个last表示已搜索的最后一辆飞机的降落时间

(2)其他部分和常见dfs代码差不多,直接看代码~

代码

注意点:

1.因为本题有n组测试数据,所以used[]注意更新为false,用于指示是否找到方案的flag也应该更新

2.一个坑点:因为写习惯了n,所以写了if(x == n)....

3.dfs(),参数更新:x + 1,max(last,t)+l,只有上一辆飞机降落且本辆飞机可以开始降落才可开始降落,即+l

#include<iostream>
#include<cstring>
using namespace std;

const int N = 100010;
struct planes{
	int t,d,l;
}p[N];
bool used[N];  //飞机是否被搜索过
int n,T;
bool flag;  //是否能找到一个方案使飞机全部降落

int dfs(int x,int last)
{
	if(x == T)  //找到一个方案
	{
		flag = true;
		return 0;
	}
	if(flag) return 0;  //只要找到一个方案就行
	for(int i = 0;i < T;i ++)
	{
		if(!used[i])
		{
			if(p[i].t + p[i].d < last) return 0;
			used[i] = true;
			dfs(x + 1,max(last,p[i].t) + p[i].l);
			used[i] = false;
		}
	}
	return 0;
}

int main()
{
	scanf("%d",&n);
	while(n --)
	{
		scanf("%d",&T);
		for(int i = 0;i < T;i ++) used[i] = false;
		flag = false;
		for(int i = 0;i < T;i ++)
		{
			scanf("%d %d %d",&p[i].t,&p[i].d,&p[i].l);
		}
		dfs(0,0);
		if(flag) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
<think>好的,我现在需要帮助用户查找蓝桥杯竞赛中与“飞机降落”相关的编程题解或算法实现。首先,我得仔细回顾用户提供的引用内容,看看哪些部分提到了飞机降落的问题。 用户提供了四个引用,其中引用[2]和引用[3]明确提到了“飞机降落”题目。引用[2]提到这是一个排序型递归的问题,需要状态函数来判断是否选过飞机,并提到了使用模板和终止条件。引用[3]进一步详细说明了递归的条件,包括如何判断飞机的最晚降落时间,以及DFS的实现细节。这两个引用应该包含了解题的关键思路和算法实现。 接下来,我需要整理这些信息,形成一个清晰的解题思路。题目可能涉及多架飞机降落顺序安排,每架飞机有特定的时间窗口,要求判断是否存在一种排列使得所有飞机安全降落。通常这类问题可以用深度优先搜索(DFS)或者回溯算法来解决,因为需要尝试所有可能的排列组合,同时进行剪枝优化。 根据引用[2]和[3],问题被转化为排序型递归,也就是排列问题,需要尝试所有可能的飞机降落顺序。在DFS过程中,需要跟踪当前的降落时间(last参数),并确保每架飞机降落时间在其允许的时间窗口内。同时,使用状态标记数组来记录哪些飞机已经被安排过,避免重复选择。 可能需要注意的细节包括:每架飞机的最早降落时间(T)和最晚开始时间(T + D),其中D是允许的盘旋时间,L是降落所需时间。每次选择一架飞机时,需要计算其实际开始降落的时间,这个时间不能早于T,也不能晚于T + D。如果满足条件,则更新last为当前飞机降落结束时间(即开始时间 + L),并继续递归处理剩余的飞机。 此外,剪枝操作非常重要,否则时间复杂度会很高。比如,当发现当前选择的顺序已经无法满足后续飞机降落条件时,提前终止该分支的搜索。 现在需要将这些思路转化为具体的代码实现。根据引用[3]的描述,代码可能包括一个DFS函数,参数包括已降落飞机的数量u,当前的时间last,以及一个状态数组标记已降落飞机。每次递归时,遍历所有未降落飞机,检查其时间窗口是否允许在当前last之后开始降落,如果可以则标记该飞机为已降落,并继续递归处理u+1的情况。 示例代码可能使用Python中的回溯方法,利用全局变量或传递状态数组来记录已选择的飞机。需要注意的是,Python中递归深度的问题,但对于蓝桥杯题目,可能的数据规模不会太大,所以DFS是可行的。 最后,用户还要求生成相关问题,我需要根据飞机降落问题涉及的算法和知识点,提出相关的问题,比如DFS的应用、剪枝优化、时间复杂度分析,或者变种问题如动态规划解法是否存在等。</think>关于蓝桥杯竞赛中“飞机降落”问题的编程实现与题解,以下为详细分析: ### 一、问题描述 飞机降落问题要求为多架飞机安排降落顺序,每架飞机有三个参数:$T_i$(最早降落时间)、$D_i$(允许的盘旋时间)、$L_i$(降落所需时间)。要求判断是否存在一种排列,使得所有飞机在时间窗口$[T_i, T_i+D_i]$内开始降落,且降落过程不冲突[^2][^3]。 --- ### 二、算法思路 #### 1. 核心方法:DFS+剪枝 - **状态定义**:使用布尔数组`st[]`标记飞机是否已降落,`u`表示已降落飞机数量,`last`表示当前最后一架飞机降落结束时间 - **递归终止条件**:当`u == n`时,所有飞机已安全降落,返回`True` - **剪枝策略**:若当前飞机的最晚开始时间$T_i+D_i$ < `last`,则无法安排,跳过该分支 #### 2. 时间复杂度优化 通过**全排列剪枝**,将时间复杂度从$O(n!)$降低到$O(n!)$(但实际运行效率因剪枝效果显著提升) --- ### 三、Python代码实现 ```python def can_land(): n = int(input()) planes = [tuple(map(int, input().split())) for _ in range(n)] st = [False] * n # 标记是否已降落 def dfs(u, last): if u == n: # 所有飞机降落完成 return True for i in range(n): if not st[i]: T, D, L = planes[i] earliest_start = T latest_start = T + D if last > latest_start: # 无法满足最晚开始时间 continue # 计算实际开始时间(取last和earliest_start的最大值) actual_start = max(last, earliest_start) st[i] = True if dfs(u + 1, actual_start + L): # 递归处理下一架飞机 return True st[i] = False # 回溯 return False return dfs(0, 0) print("YES" if can_land() else "NO") ``` --- ### 四、代码解析 1. **输入处理**:读取飞机参数并存入`planes`列表 2. **DFS函数**: - `u`记录已降落飞机- `last`记录当前最后一架飞机降落结束时间 - 遍历所有未降落飞机,检查时间窗口是否允许降落 3. **关键判断**: - `max(last, T_i)`确定实际开始时间 - `actual_start + L_i`更新为新的`last`值 4. **回溯机制**:通过`st[i]`的状态修改实现排列组合的遍历 --- ### 五、性能优化建议 1. **排序剪枝**:预处理时将$T_i$较小的飞机优先尝试 2. **记忆化搜索**:缓存已计算状态(但n较小可能收益不大) 3. **迭代加深**:限制递归深度进行优化
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值