在公交路线规划场景中,“最少乘车次数” 是典型的图论最短路径问题,其核心解法是线路级 BFS(广度优先搜索)—— 这是比传统车站级 BFS 效率高一个量级的关键思路。本文抛开冗余代码,聚焦核心逻辑与关键设计,讲透问题本质。
一、问题本质:把 “线路” 当节点的图论问题
1. 传统思路的坑
如果直接以 “车站” 为节点做 BFS,会遍历海量车站(比如城市有上百个车站),效率极低。
2. 核心优化思路
- 抽象模型:将「每条公交线路」视为图的一个节点;若两条线路有共同车站,则节点间有边(代表可换乘)。
- 问题转化:“从起点到终点最少乘车次数” = “从起点所在线路到终点所在线路的最短路径长度”。
- 效率优势:城市公交线路数(几十 / 上百条)远少于车站数,线路级 BFS 能大幅减少遍历次数。
二、核心算法:线路级 BFS 的 3 个关键步骤
步骤 1:建立 “车站→所属线路” 的映射表(核心数据结构)
这是整个算法的基础,作用是 “快速找到某个车站能换乘哪些线路”。
- 逻辑:遍历所有线路,记录每个车站对应的所有线路编号(比如车站 3 属于线路 1 和线路 2)。
- 价值:避免每次找换乘线路时重新遍历所有线路,用空间换时间。
步骤 2:BFS 初始化
- 队列存储:
(当前线路编号, 已乘车次数),初始时将起点所在的所有线路入队,乘车次数初始化为 1(坐第一条线)。 - 访问标记:用数组记录已遍历的线路,避免重复入队(防止死循环 + 提升效率)。
步骤 3:BFS 核心遍历(精华逻辑)
- 取出队列头部的线路和当前乘车次数;
- 遍历该线路的所有车站:
- 若找到终点,直接返回当前乘车次数(BFS 特性保证首次找到的是最小值);
- 若没找到,遍历该车站对应的所有线路,把未访问过的线路入队(乘车次数 + 1),并标记为已访问。
- 若队列遍历完仍未找到终点,说明无法到达。
三、关键设计点(工程化核心)
1. 输入验证与异常处理(鲁棒性)
无需纠结具体代码,核心要处理的场景:
- 车站编号为负数、非数字;
- 同一条线路内有重复车站;
- 起点 / 终点不在任何线路中;
- 线路数量为 0 或负数。→ 本质是 “过滤无效输入,提前抛出明确异常”,避免程序崩溃或计算错误。
2. 编译器兼容(适配 Dev-C++ 等老环境)
- 核心坑点:C++17 的 “结构化绑定”(
auto [a,b] = q.front())在老编译器中不支持,需替换为pair取值(q.front().first/second); - 基础要求:启用 C++11(支持范围 for、emplace、stoi 等特性)。
四、算法核心逻辑拆解(伪代码 + 关键说明)
函数 numBusesToDestination(线路列表, 起点S, 终点T): 1. 边界处理:若S==T,返回0(无需乘车) 2. 构建车站→线路映射表: 遍历每条线路(记录编号i): 遍历线路内每个车站: 映射表[车站].add(i) 3. 边界处理:若S/T不在映射表中,抛出异常(无此车站) 4. BFS初始化: 队列 = 空 访问标记数组 = 全为false 遍历S所属的所有线路: 队列.push(线路编号, 1) 访问标记[线路编号] = true 5. BFS遍历: 当队列非空: 取出当前线路cur_route、乘车次数count 遍历cur_route的所有车站: 若车站==T,返回count 遍历该车站所属的所有线路next_route: 若next_route未访问: 访问标记[next_route] = true 队列.push(next_route, count+1) 6. 返回-1(无法到达)伪代码关键解读
- 第 5 步中,“遍历当前线路的车站→找换乘线路” 是核心:每找到一条新线路,就代表 “多坐一次车”;
- BFS 的 “层级遍历” 特性保证了 “首次找到终点时的 count 是最小值”—— 这是 BFS 解决最短路径问题的核心原因。
五、核心亮点与扩展方向
1. 核心优势
- 效率:线路级 BFS 比车站级 BFS 减少 80% 以上的遍历次数;
- 鲁棒性:提前处理边界场景(无效输入、无此车站等),避免异常;
- 兼容性:适配老编译器,兼顾工程实用性。
2. 扩展优化(无需改核心逻辑)
- 性能优化:用
unordered_map替代map(哈希表查询更快); - 功能扩展:记录换乘路径(在队列中额外存储 “路径信息”,比如坐了哪些线路);
- 数据持久化:将线路数据读写到文件,无需每次重新输入。
六、总结
解决 “公交最少乘车次数” 问题的核心,不是堆代码,而是把 “线路” 抽象为图的节点—— 这是从 “暴力遍历” 到 “高效求解” 的关键。线路级 BFS 的核心逻辑只有 3 步:建映射表、初始化队列、层级遍历线路,其余代码(输入验证、异常处理等)都是工程化补充,不影响算法本质。
这个思路不仅适用于公交路线,还可迁移到 “地铁换乘”“物流中转” 等所有 “节点分组 + 最短中转次数” 类问题,是图论 BFS 的经典应用范式。