返回算法课程
图与搜索进阶

Dijkstra 最短路Dijkstra

反复确定当前最近的节点,再用它改善邻居的候选距离。

25 分钟前置:图 · BFS · 贪心思想

01先从一个问题出发

道路耗时不一样时,最少经过道路不代表最早到达。需要按累计代价扩展。

一个具体的例子

0→1 耗时 4,0→2 耗时 2,2→1 耗时 1;经过 2 到 1 只需 3。

02最直接的办法,为什么慢?

枚举所有简单路径计算代价。

暴力 · 最坏 O(V!) 条路径

大量路径共享相同前缀,候选数量可呈阶乘级增长。

03一步步,推导出优化思路

1

发现可以复用的信息

给每个节点维护当前已知最小距离 dist。

2

建立可维护的状态

非负边权保证:未确定节点中 dist 最小的节点,距离可以最终确定。

3

消除重复工作

用这个节点尝试松弛每条出边,再选择下一个最近节点。

贯穿算法的不变量

已确定节点的距离就是最短路;未确定节点记录目前已发现路径的最小代价。

04让每一步,都看得见

试着先预测下一步,再点击「下一步」验证。变量、动画与代码会同步变化。

Dijkstra交互演示
STEP 01 / 34
42158230d = 01d = 2d = 3d = 4d = 5d =
无向图 · 源点 0 · 邻居按编号处理
当前处理已处理 / 已确定未处理
01

源点为 0。其距离为 0,其余暂为无穷大。所有边权必须非负。

dijkstra.py参考实现 · 当前第 4 行
正在载入代码编辑器…

动画展示参考实现的执行轨迹。切换语言时,当前操作会定位到对应代码行。

05复杂度,来自具体的工作量

时间复杂度
O(V2+E)O(V^2+E)

本课采用直观的线性选最小值:V 次选择,每次扫描 V 个节点,加上所有边的松弛。二叉堆版本可改善到 O((V+E)log V)。

辅助空间
O(V)O(V)

dist、visited 和候选节点集合都是 O(V),不含输入邻接表。

拖动 n,看看增长速度

06看到什么,应该想到它?

这些特征值得停下来想一想:

关键词只是线索,继续检查适用条件

07这些细节,容易踩坑

01

不能处理负权

负权会破坏已确定距离不会变小的证明,应考虑 Bellman–Ford。

02

不可达不是 0

不可达节点距离保持为 ∞。

08把想法带进真实题目

先说出模式和适用条件,再开始写代码。

09不用背模板,回答这几个问题

01Dijkstra 的关键前提?

02松弛是什么?

03本课线性选点版本的时间复杂度?

你已经走完了这次推导。

能用自己的话解释复杂度和不变量,再标记为掌握。

把知识连起来