目录
题目:
题目描述:
题目链接:
思路:
核心思路:
DFS
思路详解:
看到题目的第一想法可能是贪心,但是贪心不好确定飞机起飞的顺序。看到数据范围1<=T<=10,数据很小,可以用全排列DFS来做,在DFS过程中还可以提前剪枝提高效率。清楚是用DFS做后,难点是理清题目给的各种时间,如果搞混理不清也还是不好做出来的。具体的思路结合代码和注释会更好理解
代码:
代码详解:
#include<bits/stdc++.h> //还没有学贪心,看题解说第一想法是贪心但是不好确定顺序,n<=10数据很小dfs
using namespace std;
const int N=15; //开大一点,防止数组越界
int T,n; //T表示输入数据的组数,一开始用的t然后和下面的t[N]变量名冲突了
int t[N],d[N],l[N]; //t表示每架飞机最早降落时刻,d表示可以盘旋的时间,l表示降落过程需要的时间
bool state[N]; //state用于记录每架飞机是否枚举过,=false表示没有被枚举,=true表示枚举过
//state定义为全局数组中途修改不会再初始化,所以每组数据都要memset来初始化
bool flag; //flag用于标记是否能够全部降落,=false表示全排列所有飞机降落的顺序都不可以安全降落
//=true表示全排列至少有一种顺序可以安全降落,全局变量flag也是每组数据都要初始化
void dfs(int u,int time) //u表示现在枚举的第u个降落的飞机,time表示目前的时间
{
if(u>n) //判断边界,如果存在能递归到u>n的枚举方案,就表示至少有一个可行解
{
flag=true; //只要有一个可行解就标记flag=true
return; //记得return退出
}
for(int i=1;i<=n;i++) //遍历所有的飞机,由题第i架飞机,所以i从1开始
{
if(state[i]==true||t[i]+d[i]<time) //提前剪枝,提高效率,如果当前飞机被枚举过,或当前飞机最
{ //晚的降落时间<当前时间,t+d表示最晚的降落时间
continue; //跳过当前飞机,分析下一个
}
state[i]=true; //能走到这说明当前飞机没被枚举过且最晚降落时间>=当前时间,先标记被枚举过
dfs(u+1,max(t[i],time)+l[i]); //u+1很好理解,由上当前飞机最晚时间t+d>=当前时间就说明这架
//飞机一定能成功降落,由于一架飞机降落完毕时,另一家飞机可以立即在同一时刻开始降落,我们判断
//的目标是全部飞机能全部安全降落,所以当前飞机以时间范围允许的最早时间降落即可,t表示最早
//降落时间,time表示当前时间,如果t[i]>time那只能等到t[i]时刻才能最早降落,如果t[i]<time那
//当前时间就是最早降落时间,转换为代码就是max(t[i],time),因为传的参数是当前时间还要+l[i]
state[i]=false; //恢复现场
}
return; //上面的for循环枚举了所有飞机全排列的方案,只要是没有递归到u>n就说明不可行
}
int main()
{
cin>>T;
for(int i=0;i<T;i++)
{
flag=false; //flag是全局变量,一旦改变就不会再初始化,所以每组数据开始前先初始flag=false
memset(state,false,sizeof state); //state是全局变量,同理用memset每组数据都先初始化为false
cin>>n;
for(int j=1;j<=n;j++)
{
cin>>t[j]>>d[j]>>l[j];
}
dfs(1,0);
if(flag==true) //在所有全排列方案中只要出现一个可行解flag就会等于true
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}