机试题——最好的通勤体验

题目描述

小明每天上班需要从家出发,经过一个早餐店买早餐,最后到达公司。他可以选择乘坐多条公交线路,每条线路都是单向循环行驶的。目标是找到一种方案,使得小明乘坐的公交车总数最少。如果无法找到这样的方案,则输出 -1

输入描述

  1. 第一行包含三个数字,分别表示上车的公交站台编号、早餐店的公交站台编号、下车公交站台编号,依次用空格隔开。
  2. 第二行表示公交路线数量,后续的每一行中第一个数字代表该路线的总站台数,剩余的数字表示每条公交路线经过的站点编号,所有数字用空格隔开。
  3. 公交路线数量范围在 [1, 500]。
  4. 公交站台的编号范围在 [1, 1000000]。
  5. 每条公交路线经过的站台数量范围在 [2, 1500],路线中的站台编号按升序顺序排序,且每条路线中不包含重复的站台。
  6. 起点站台、购买早餐的站点、终点站台不重复。

输出描述

输出乘坐的公交路线总数,如果没有匹配的路线请返回 -1

用例输入

输入:

1 3 5
4
3 1 2 6
3 2 3 7
3 5 6 8
2 5 7

输出:

3

说明:
先乘坐第 1 条公交路线的车,在第 2 个站点下车转第 2 条路线的公交车,然后在站点 3 下车买早餐,再乘坐第 2 条公交路线达到站点 7 下车转第 4 条公交路线,最后达到站点 5。

解题思路

问题分析

  1. 目标:找到从起点到终点的最短乘车线路数。
  2. 关键点
    • 必须经过早餐店。
    • 可以在任何站点换乘。
    • 使用广度优先搜索(BFS)来找到最短路径。

算法设计

  1. 数据结构

    • 使用二维数组 bus 存储每条公交线路的站点。
    • 使用 trans 存储每个站点可以乘坐的公交线路。
    • 使用 dis 数组记录从起始点到每个公交线路的最短距离。
  2. BFS

    • 从早餐店开始,使用 BFS 搜索从早餐店到每条公交线路的最短距离。
    • 对于每个可以到达早餐店的公交线路,再从该线路的起点到早餐店的距离,加上早餐店到终点的距离,计算总距离。
  3. 结果计算

    • 如果无法从早餐店到终点,则输出 -1
    • 否则,输出从起点到早餐店再到终点的最短距离。

代码

#include
#include
#include
#include
#include
#include
using namespace std;

int st_id, m_id, e_id; // 输入起点、早餐店、终点的站点 id
int n; // 线路数量
vector<vector<int>> bus; // 公交车线路
map<int, vector<int>> trans; // 站点对应的公交线路

// 打印函数
void print(vector<int> nums) {
    for (int i = 0; i < nums.size(); i++) {
        cout << nums[i];
        if (i != nums.size() - 1) cout << " ";
    }
}

// 广度优先搜索
vector<int> bfs(int be) {
    int n = bus.size();
    vector<int> dis(n, -1);  // 距离数组,初始值为-1,表示未访问的公交线路
    queue<int> q;  // 用于广度优先搜索的队列
    q.push(be);
    dis[be] = 0;
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        // 该公交线路的所有站点
        for (int nex : bus[cur]) {
            // 该线路的站点
            for (int nex_id : trans[nex]) {
                if (dis[nex_id] == -1) {
                    dis[nex_id] = dis[cur] + 1;
                    q.push(nex_id);
                }
            }
        }
    }
    return dis;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> st_id >> m_id >> e_id; // 输入起点、早餐店、终点的站点编号
    cin.ignore();
    cin >> n; // 输入公交路线数量
    bus.resize(n); // 初始化公交车线路数组
    for (int i = 0; i < n; i++) {
        int m;
        cin >> m;  // 读取站点数量
        bus[i].resize(m);
        for (int j = 0; j < m; j++) {
            cin >> bus[i][j];  // 读取每个站点
        }
    }
    for (int i = 0; i < n; i++) {
        for (int x : bus[i]) {
            trans[x].push_back(i); // 填充每个站点可以到达的公交线路
        }
    }
    long long res = INT_MAX; // 初始化结果为最大值
    // 从早餐店出发,计算到各个公交线路的最短距离
    for (int id : trans[m_id]) {
        vector<int> dis = bfs(id); // BFS 搜索从早餐店出发的最短路径
        long long be_to_mid = INT_MAX; // 起点到早餐店的最短距离
        for (int bus_id : trans[st_id]) {
            if (dis[bus_id] == -1) continue; // 如果无法到达该线路,则跳过
            be_to_mid = min(be_to_mid, (long long)dis[bus_id]); // 更新最短距离
        }
        long long mid_to_ed = INT_MAX; // 早餐店到终点的最短距离
        for (int bus_id : trans[e_id]) {
            if (dis[bus_id] == -1) continue; // 如果无法到达该线路,则跳过
            mid_to_ed = min(mid_to_ed, (long long)dis[bus_id]); // 更新最短距离
        }
        if (be_to_mid == INT_MAX || mid_to_ed == INT_MAX) continue; // 如果无法到达,则跳过
        res = min(res, be_to_mid + mid_to_ed + 1); // 更新结果
    }
    if (res == INT_MAX) cout << -1; // 如果无法到达终点,则输出 -1
    else cout << res; // 输出最短路径
    return 0;
}

你可能感兴趣的:(#,hw机试题,算法,数据结构,c++)