61.阿D的最佳飞行路线探索|Marscode AI刷题

3 阅读4分钟

1.题目

问题描述

小C和他的领导小F计划一次飞行,但由于严格的航空管制,他们的飞机仅能按特定的路线飞行:飞机只能飞往当前机场的相邻机场或相同航空公司管理的机场。为了减少起飞次数,小C需要制定最优的飞行路线。机场由一个数组airports标识,其中:

  • 数组每个元素代表一个独特的机场,元素的值代表不同的航空公司。
  • airports[0]为起点,airports[airports.length - 1]为终点。
  • 假设小C当前在机场i,那么i - 1i + 1(如果存在)代表邻近机场,飞机可以直接前往。
  • 如果在机场i,且存在airports[i] == airports[j],则机场i和机场j同属一家航空公司,可直接飞往。

求最小起飞次数。


测试样例

样例1:

输入:airports = [10, 12, 13, 12, 14]

输出:3

样例2:

输入:airports = [10, 11, 12, 13, 14]

输出:4

样例3:

输入:airports = [7, 7, 7, 8, 9, 7]

输出:1

2.思路

bfs

  • 构造辅助数据结构:

    • **航空公司映射:**使用一个哈希表(unordered_map<int, vector<int>>),将每个航空公司编号映射到该航空公司所管理的所有机场的下标。这样,当访问到某个机场时,可以直接获得同一家航空公司的所有其他机场下标,进行快速跳转。
  • 利用广度优先搜索(BFS)寻找最短路径:

    • **初始状态:**从起点(下标 0)开始,将其加入队列,并标记为已访问。

    • **逐层扩展:**使用 BFS 的层级遍历,每一层对应一次跳转。每层处理时:

      • 对当前队列中所有节点,依次检查:a. 是否已到达终点;b. 当前节点的左侧和右侧相邻机场(如果存在且未访问),将它们加入队列;c. 当前节点所属航空公司的所有其他机场(如果未访问),也加入队列。
      • 为防止重复跳转,每次处理完某航空公司的所有机场后,可以清空该航空公司的列表。
    • **步数计数:**每处理完一层,将步数加 1。这样当首次遇到终点时,当前步数就是所需的最小跳转数。

  • 返回结果:

    当找到终点时,返回对应的跳转步数。

3.代码

先飞到最远的相同航空公司管理的机场,再飞相邻机场,这样的思路不一定能找到最优飞行路线

#include <iostream>
#include <vector>

int solution(std::vector<int> airports) {
    // Please write your code here
    int i = 0;
    int n = airports.size();
    int cnt = 0;
    bool flag = false; //是否有相同机场的飞机 
    while (i != n - 1) {
        for (int j = n - 1; j > i; j--) {
            flag = false;
            if (airports[i] == airports[j]) {
                i = j;
                cnt ++;
                flag = true;
            }
        }
        if (!flag ) {
            i++;
            cnt++;
        }
    } 
    return cnt;
}

int main() {
    //  You can add more test cases here
    std::vector<int> airports1 = {10, 12, 13, 12, 14};
    std::vector<int> airports2 = {10, 11, 12, 13, 14};

    std::cout << (solution(airports1) == 3) << std::endl;
    std::cout << (solution(airports2) == 4) << std::endl;
    return 0;
}

bfs

#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;

int solution(std::vector<int> airports) {
    // Please write your code here
    int n = airports.size();
    if (n == 1) {
        return 0; //只有一个机场,不需要起飞
    }
    // 1.初始化数据结构
    unordered_map<int, vector<int>> airlineMap;
    for (int i = 0; i < n; ++i) {
        airlineMap[airports[i]].push_back(i);
    }
    queue<int> q;
    vector<bool> visited(n, false);

    // 2.BFS初始化
    q.push(0);
    visited[0] = true;
    int steps = 0;

    // 3.BFS遍历
    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; ++i) {
            int current = q.front();
            q.pop();

            // 检查是否到达目的地
            if (current == n - 1) {
                return steps;
                }

            // 检查相邻机场
            if (current - 1 >= 0 && !visited[current - 1]) {
                q.push(current - 1);
                visited[current - 1] = true;
                }
            if (current + 1 < n && !visited[current + 1]) {
                q.push(current + 1);
                visited[current + 1] = true;
                }
            // 检查同一公司的机场
            for (int next : airlineMap[airports[current]]) {
                if (!visited[next]) {
                q.push(next);
                visited[next] = true;
                }
            }
            // 清空当前航空公司机场列表,避免重复访问
            airlineMap[airports[current]].clear();
            }
            steps++;
    }
    return steps;
}

int main() {
    //  You can add more test cases here
    std::vector<int> airports1 = {10, 12, 13, 12, 14};
    std::vector<int> airports2 = {10, 11, 12, 13, 14};

    std::cout << (solution(airports1) == 3) << std::endl;
    std::cout << (solution(airports2) == 4) << std::endl;
    return 0;
}

在广度优先搜索(BFS)算法中,我们通常会使用一个外层的循环来逐层(按距离)遍历节点。具体来说:

  • 层级遍历:

    变量 steps 记录的是从起点到当前节点所经过的步数。在 BFS 中,每次从队列中取出所有当前层的节点(即距离起点相同步数的节点),然后再把它们的相邻节点加入队列,这样相邻节点就都在下一层。

    这个 for (int i = 0; i < size; ++i) 循环的作用就是遍历当前队列中所有节点(当前层的节点),确保我们在将 steps 增加前,已经把同一层的所有节点都处理完毕。

  • 计数步数:

    这样设计可以确保每增加一层就代表多走了一步,进而准确计算到达目的地所需的最小步数。

简而言之,这个循环保证了我们按层级遍历节点,从而正确计算最短路径(或者说最少的步骤数)。

4.参考资料

阿D的最佳飞行路线探索 | 豆包MarsCode AI刷题阿D的最佳飞行路线探索,已知飞机只能飞向当前机场的前后相邻机场 - 掘金