目录
题目
代码
AC结果
思路
〇、例子
一、获取数据
二、深度优先遍历(DFS)
1.入参
2.出口
3.判断是否找到安全降落方案
4.递推过程
5.回溯过程
6.DFS完整代码
三、输出打印
题目
4957. 飞机降落 - AcWing题库 https://www.acwing.com/problem/content/description/4960/
https://www.acwing.com/problem/content/description/4960/
代码
import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int T = input.nextInt();//数据组数
		for(int i = 0; i < T; i++) {
			int N = input.nextInt();//飞机数
			int[][] a = new int[N + 1][3];
			a[0][0] = 0;//Ti
			a[0][1] = 0;//Di
			a[0][2] = 0;//Li
			for(int j = 1; j < N + 1; j++) {
				a[j][0] = input.nextInt();
				a[j][1] = input.nextInt();
				a[j][2] = input.nextInt();
			}
			boolean[] state = new boolean[N + 1];//记录飞机降落状态
			boolean[] flag = new boolean[1]; 
			flag[0] = false;//记录是否找到安全的降落方案
			
			dfs(0,state,flag,0,N,a);
			
			//输出打印
			if(flag[0]) {
				System.out.println("YES");
			}else {
				System.out.println("NO");
			}
			
		}
	}
	
	//深度优先搜索
	public static void dfs(int k,boolean state[],boolean[] flag,int t,int N,int a[][]) {  //t记录时刻
		//出口
		if(flag[0]) {
			return;
		}
		//判断是否为可行方案
		if(k == N) {
			flag[0] = true;
		}
		for(int i = 1; i < state.length; i++) {
			if(!state[i]) {//第i架飞机没有降落
				int tempt = t;
				if(t <= a[i][0] + a[i][1]) {//可以降落
					state[i] = true;
					if(t < a[i][0]) {//等飞机到了再降落
						t = a[i][0] + a[i][2];
					}else {//a[i][0] < t < a[i][0] + a[i][1]  飞机已经到了,直接降落
						t = t + a[i][2];
					}
				}else{//t > a[i][0] + a[i][1]->炸了
					return;
				}
				dfs(k+1,state,flag,t,N,a);
				
				//恢复
				state[i] = false;
				t = tempt;
			}
		}
	}
}
AC结果

思路
这道题的解题思路的本质就是枚举,将所有可能降落的顺序都枚举一遍,判断在所有的方案中,是否存在一个安全的降落方案。利用深度优先搜索(DFS)实现上述想法,将所有降落顺序按照树的形式排列,然后采取深度优先对树进行遍历。利用一个boolean类型的flag记录是否找到安全降落的方案,若有则将其值改为true,否则为flase。最后,每一组数据根据flag的值输出“YES”或“NO”即可。
〇、例子

以下面这组数据为例。有3架飞机,一共有6种可能的降落方案,接着一一判断是否可行。
1-2-3不可行
1-3-2不可行
2-1-3不可行
2-3-1不可行
3-1-2不可行
3-2-1可行
所以输出“YES”
1
3
0 100 10
10 10 10
0 2 20一、获取数据
T表示数据组数;
N为某组中的飞机数;
a[i][0]为Ti,表示该组第i架飞机到达机场的时刻;
a[i][1]为Di,表示该组第i架飞机到达机场后可盘旋的时间;
a[i][0]为Li,表示该组第i架飞机降落所需耗时;
state记录第i架飞机的降落状态(是否已降落);
flag记录是否找到可行的安全降落方案;
		Scanner input = new Scanner(System.in);
		int T = input.nextInt();//数据组数
		for(int i = 0; i < T; i++) {
			int N = input.nextInt();//飞机数
			int[][] a = new int[N + 1][3];
			a[0][0] = 0;//Ti
			a[0][1] = 0;//Di
			a[0][2] = 0;//Li
			for(int j = 1; j < N + 1; j++) {
				a[j][0] = input.nextInt();
				a[j][1] = input.nextInt();
				a[j][2] = input.nextInt();
			}
			boolean[] state = new boolean[N + 1];//记录飞机降落状态
			boolean[] flag = new boolean[1]; 
			flag[0] = false;//记录是否找到安全的降落方案二、深度优先遍历(DFS)
1.入参
public static void dfs(int k,boolean state[],boolean[] flag,int t,int N,int a[][]) { k表示已经降落的飞机数;
state数组表示各个飞机的降落状态;
flag[0]记录是否已经找到安全的降落方案;
t表示当前时刻;
N表示该组共有的飞机数;
a数组是一个三维数组,分别记录了每架飞机的到场时刻,可盘旋时间和降落耗时;
2.出口
		//出口
		if(flag[0]) {
			return;
		}当flag[0]为true时,一路回溯即可。
3.判断是否找到安全降落方案
		//判断是否为可行方案
		if(k == N) {
			flag[0] = true;
		}当已降落飞机数k等于该组飞机总数N时,即代表已经找到了安全可行的降落方案。
4.递推过程
		for(int i = 1; i < state.length; i++) {
			if(!state[i]) {//第i架飞机没有降落
				int tempt = t;
				if(t <= a[i][0] + a[i][1]) {//可以降落
					state[i] = true;
					if(t < a[i][0]) {//等飞机到了再降落
						t = a[i][0] + a[i][2];
					}else {//a[i][0] < t < a[i][0] + a[i][1]  飞机已经到了,直接降落
						t = t + a[i][2];
					}
				}else{//t > a[i][0] + a[i][1]->炸了
					return;
				}
				dfs(k+1,state,flag,t,N,a);遍历state数组,找到哪一架飞机尚未降落。需要用一个tempt变量记录,当前时刻,一边后续回溯时使用。然后判断当前时刻t是否小于等于t <= a[i][0] + a[i][1](飞机到场时刻+余油可盘旋时间=最迟降落时刻),若满足则表示这架飞机是可以降落的(具体细分为两种情况),若不满足则这架飞机得坠机,因此这个方案不可行需要return回溯。
如果经过上述判断,确定该架飞机可以降落,有两种情况:
(1)t<a[i][0],即当前时刻小于该架飞机到场时刻。说人话就是,飞机还没飞到机场,得等飞机到机场才能开始降落。
(2)a[i][0] <= t < a[i][0] + a[i][1],当前时刻在飞机可降落的范围之内。说人话,上一架飞机完成降落,下一架飞机可以马上接着进行降落。
若当前飞机可以降落,可以再调用dfs方法,进行下一层的递推判断。若存在安全可行的降落方案,将在递推的过程中产生并判断出来。
5.回溯过程
如果当前的降落方案不可行,飞机炸了,则需要回溯到上一层选择其他降落顺序。回溯到上一层之前,需要将以下变量恢复,state[i]需要恢复为false(表示第i架飞机并没有完成降落),时间也将倒流回到tempt时刻。
6.DFS完整代码
	//深度优先搜索
	public static void dfs(int k,boolean state[],boolean[] flag,int t,int N,int a[][]) {  //t记录时刻
		//出口
		if(flag[0]) {
			return;
		}
		//判断是否为可行方案
		if(k == N) {
			flag[0] = true;
		}
		for(int i = 1; i < state.length; i++) {
			if(!state[i]) {//第i架飞机没有降落
				int tempt = t;
				if(t <= a[i][0] + a[i][1]) {//可以降落
					state[i] = true;
					if(t < a[i][0]) {//等飞机到了再降落
						t = a[i][0] + a[i][2];
					}else {//a[i][0] < t < a[i][0] + a[i][1]  飞机已经到了,直接降落
						t = t + a[i][2];
					}
				}else{//t > a[i][0] + a[i][1]->炸了
					return;
				}
				dfs(k+1,state,flag,t,N,a);
				
				//恢复
				state[i] = false;
				t = tempt;
			}
		}
	}三、输出打印
根据flag[0]的值可以知道是否找到安全降落的方案,然后对应输出“YES”和“NO”即可。
			//输出打印
			if(flag[0]) {
				System.out.println("YES");
			}else {
				System.out.println("NO");
			}


















