非常好,“单源最短路问题”是图论与算法中的重要经典问题之一。在深入数据结构或算法学习中,这是理解“权值图 + 贪心 / 动态规划思想”的重要节点。下面我将为你完整整理这一章节的内容,标题为:
《领略算法真谛》
单源最短路问题——解构路径的最优解
📘 一、什么是单源最短路问题?
定义:在一个带权有向或无向图中,给定一个源点 s,求从 s 到图中所有顶点的最短路径(路径权值和最小)。
- 输入:图 G=(V,E)、源点 s、边权重 w(u,v)≥0
- 输出:从源点 s 到所有其它顶点的最短路径及其路径长度
🛣️ 二、经典算法总览
算法 | 适用图类型 | 时间复杂度 | 特点 |
---|---|---|---|
Dijkstra | 非负权图 | O((V+E) log V) | 贪心,效率高,常用 |
Bellman-Ford | 可含负权边 | O(VE) | 可检测负权环 |
SPFA | Bellman-Ford优化 | 平均较快 | 某些图极快,最坏 O(VE) |
Floyd | 所有点对点最短路 | O(V³) | 静态图处理 |
🧠 三、Dijkstra 算法详解(重点)
✅ 1. 算法思想
使用贪心策略,逐步扩展最短路径集合。
- 初始将源点加入“已确定集合”
- 每次选择离源点最近的未访问节点
- 更新它的邻居的最短路径估计
- 重复直到所有点确定最短路径
✅ 2. 伪代码(使用优先队列优化)
import heapq
def dijkstra(graph, start):
dist = {v: float('inf') for v in graph}
dist[start] = 0
visited = set()
heap = [(0, start)]
while heap:
d, u = heapq.heappop(heap)
if u in visited:
continue
visited.add(u)
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(heap, (dist[v], v))
return dist
✅ 3. 图示说明(描述)
假设图如下:
2 1
A ------ B ------ C
\ |
\5 |3
\ v
------ D
- 源点 A
- 初始:
dist[A]=0
, 其它无穷大 - 每次选择当前
dist
最小的点扩展路径
🧨 四、Bellman-Ford 算法详解(处理负权图)
✅ 1. 核心思想
- 动态规划,每轮尝试“松弛”所有边
- 共执行 V-1 轮松弛,确保最短路径
- 第 V 轮再松弛一次,若还能更新则说明有负权环
✅ 2. 使用场景
- 图中有负权边,不能用 Dijkstra
- 适用于金融、货币兑换等涉及负值的图模型
⚡ 五、SPFA(Shortest Path Faster Algorithm)
是 Bellman-Ford 的队列优化版本,平均效率比 Dijkstra 还快
✅ 思路:
- 每次只处理在队列中的点
- 避免无谓松弛,适用于稀疏图
- 可能退化成 Bellman-Ford,最坏 O(VE)
🧮 六、算法对比图表
特性 | Dijkstra | Bellman-Ford | SPFA |
---|---|---|---|
负权边支持 | ❌ | ✅ | ✅ |
是否稳定(一定最短) | ✅ | ✅ | ✅ |
是否贪心策略 | ✅ | ❌ | ❌ |
是否可检测负环 | ❌ | ✅ | ✅ |
时间复杂度 | O((V+E)logV) | O(VE) | 平均 O(E) |
📌 七、实际应用场景举例
场景 | 描述 |
---|---|
地图导航 | Dijkstra 最常见,用于地图系统 GPS |
网络延迟优化 | 求最短时延路径 |
货币兑换 | Bellman-Ford 检测套利环 |
电信路由优化 | SPFA 处理大规模路由计算 |
游戏AI路径规划 | 简化版 Dijkstra 用于角色寻路 |
🧭 八、总结口诀
最短路径靠贪心,负权要用 Bell;Dijkstra 用堆加速,SPFA 帮你省时间。
发表回复