AcWing 4957. 飞机降落 -- dfs

题目

\(N\) 架飞机准备降落到某个只有一条跑道的机场。

其中第 \(i\) 架飞机在 \(T_i\) 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 \(D_i\) 个单位时间,即它最早可以于 \(T_i\) 时刻开始降落,最晚可以于 \(T_i + D_i\) 时刻开始降落。

降落过程需要 \(L_i\) 个单位时间。

一架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。

请你判断 \(N\) 架飞机是否可以全部安全降落。

输入格式

输入包含多组数据。

第一行包含一个整数 \(T\),代表测试数据的组数。

对于每组数据,第一行包含一个整数 \(N\)

以下 \(N\) 行,每行包含三个整数:\(T_i\)\(D_i\)\(L_i\)

输出格式

对于每组数据,输出 YES 或者 NO,代表是否可以全部安全降落。

数据范围

对于 \(30\%\) 的数据,\(N ≤ 2\)
对于 \(100\%\) 的数据,\(1 ≤ T ≤ 10\)\(1 ≤ N ≤ 10\)\(0 ≤ T_i, D_i, L_i ≤ 10^5\)

输入样例:

2
3
0 100 10
10 10 10
0 2 20
3
0 10 20
10 10 20
20 10 20

输出样例:

YES
NO

样例解释

对于第一组数据,可以安排第 \(3\) 架飞机于 \(0\) 时刻开始降落,\(20\) 时刻完成降落。安排第 \(2\) 架飞机于 \(20\) 时刻开始降落,\(30\) 时刻完成降落。安排第 \(1\) 架飞机于 \(30\) 时刻开始降落,\(40\) 时刻完成降落。

对于第二组数据,无论如何安排,都会有飞机不能及时降落。

题解

这道题数据范围非常小 \(1≤N≤10\) 所以我们采用dfs暴搜的方法 核心代码与基础课里dfs排列数字类似
6ee524681306e31f103f482ef2904f1.jpg
本质就是我们将这些无序的区间(表示飞机的到达时间T、最晚开始降落时间T+D、降落时间L) 像排列数字一样排列出不同的方案 选出其中能使所有区间均不重叠的方案,就能使全部飞机成功降落

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 15;

int n;
bool st[N]; //判断该飞机有没有降落

struct Plane //用结构体定义一架飞机的三个属性
{
    int t, d, l;
}p[N];

bool dfs(int u, int last) //u表示已经降落的飞机数量,last表示上一架飞机降落完成的时间
{
    if (u == n) return true; //u的范围是0~n-1 当u=n时,表示所有飞机已经降落

    for (int i = 0; i < n; i ++ )
    {
        int t = p[i].t, d = p[i].d, l = p[i].l;
        if (!st[i] && t + d >= last) //如果该飞机没有降落 并且 该飞机最晚降落时间 >= 上一家飞机降落时间
        {
            st[i] = true;
            if(dfs(u + 1, max(t, last) + l)) return true; //该飞机降落后向下搜索下一架飞机是否能降落 max(t, last)是取 上一架飞机降落时间 和 该飞机到达机场时间 取最大值,
                                                       // 目的是看该飞机最终是啥时候开始降落的(不能在上一架飞机降落时就降落也不能在还没到机场时就降落)再加上本次飞机降落时间l,就是本次飞机降落完成时间
                                                       //如果递归到dfs(n - 1, last)也能进入if(!st[i] && t + d >= last)(也就是最后一架飞机也可以正常降落) 那么if内我们就会递归到下一层dfs(n, last)最终u==n返回true
                                                       //返回到if(dfs(u + 1, max(t, last) + l))成立,继续return true,不断返回,最终返回到dfs(0, 0) 最终函数就会return true
            st[i] = false; //进行到这里表示上一句话没有return true 也就是下一架飞机不能降落 那么恢复现场,保证这架飞机可以在下一次for循环被继续利用
        }

    }
    return false; //如果循环内没有搜索到可以将全部飞机成功降落的顺序,就返回false
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d", &n);
        for (int i = 0; i < n; i ++ )
        {
            int t, d, l;
            scanf("%d%d%d", &t, &d, &l);
            p[i] = {t, d, l};
        }
        memset(st, 0, sizeof st); //每次排列飞机降落顺序前都要把标记数组清空,防止被上一组数据影响(每次会测试很多组数据T)
        if (dfs(0, 0)) puts("YES"); //从已经降落的飞机数量为0 降落时间为0的点开始搜索
        else puts("NO");
    }

    return 0;
}
posted @ 2024-04-16 17:34  MsEEi  阅读(75)  评论(0)    收藏  举报