news 2026/10/11 12:14:02

大学图论第 4 讲:最短路三件套——Dijkstra 为什么怕负权,Floyd 的三重循环凭什么正确

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大学图论第 4 讲:最短路三件套——Dijkstra 为什么怕负权,Floyd 的三重循环凭什么正确

大家好,我是熊猫钓鱼,欢迎大家点赞关注!

《把定理跑出来》系列第 4 讲。最短路是图论课的绝对核心,也是考研计算题的最大的题源。Dijkstra、Bellman-Ford、Floyd 三个名字背得滚瓜烂熟,但"为什么一个怕负权、一个不怕、一个连负环都能查"——背是背不出来的,跑一遍就懂了。

本讲 8 张图全部由文末代码生成,种子固定(SEED=2026),可复现。所有算法均为手写课本实现,两两对拍。

摘要

  • Dijkstra 负权失效实测:4 顶点反例(0→1 权 1、0→2 权 2、2→1 权−2、1→3 权 1)上,课本版 Dijkstra 给出 dist[3]=2.0,真最优是1.0(0→2→1→3)——误差 100%,且毫无报警;
  • 对拍边界:正权随机图200 组零分歧;87 组含负权(无负环)图上,"允许重访"的堆版 Dijkstra意外全部答对——但同一实现在含负环的图上直接死循环 8 分钟(调试实录),dist 沿负环每圈递减、堆无限膨胀;
  • Bellman-Ford 早停:随机图实际收敛轮数 5.3~6.7 轮,远小于理论上限 V−1(49~399 轮)——但复杂度仍按最坏算;
  • Floyd 的 k:k 轮 = 只允许中转点 {0…k−1} 的最短路,5 联热图逐轮演示 ∞ 消失与数值下降;Floyd vs 逐源 Dijkstra 60 组对拍零分歧,路径重建(next 矩阵)与 prev 树重建30/30代价一致;
  • 规模横评:稠密图 n=400——Dijkstra 1.84ms、Bellman-Ford 10.03ms、Floyd2155ms;稀疏图上 Bellman-Ford 只比 Dijkstra 慢约 2 倍——O(VE) 与 O((n+e)logn) 的理论差距被常数吃掉(第 3 篇的教训再次应验);
  • 负环检测:Floyd(对角线变负)与 Bellman-Ford(第 V 轮仍可松弛)两个独立实现的检测器在负环 fixture 上结论一致。

关键词:Dijkstra;Bellman-Ford;Floyd;负权边;负环;松弛;动态规划;路径重建;复杂度实测

目录

  • 1. 三件套的一句话分工
  • 2. Dijkstra 怕负权:课本反例实测
    • 2.1 三层真相:课本版错、堆版侥幸、负环必死
    • 2.2 对拍:正确性的边界就是"非负"两字
  • 3. Bellman-Ford:允许"后悔"的算法
    • 3.1 实际轮数远小于 V−1
  • 4. 负环检测:两个检测器互相校验
  • 5. Floyd:三重循环凭什么正确
  • 6. 规模横评:两条 n³ 的曲线与一条 n² 的曲线
  • 7. 选型元图
  • 8. 本讲检查清单
  • 9. 复现指南
  • 10. 下一讲预告

1. 三件套的一句话分工

先给结论版的地图,后面的实验负责让这张地图"长出来":

  • Dijkstra:贪心。前提"边权非负",单源最快;
  • Bellman-Ford:动态规划式的反复松弛。允许负权、能查负环,代价 O(VE);
  • Floyd:动态规划。一次算出所有点对的最短路,O(n³) 换 10 行代码。

2. Dijkstra 怕负权:课本反例实测

图 1:课本经典反例。边 0→1 权 1、0→2 权 2、2→1 权−2、1→3 权 1。Dijkstra 的贪心顺序是:确定 1(dist=1)→ 确定 2(dist=2)→ 2 的松弛想把 1 更新为 2−2=0——但 1 已经"确定",更新被永久关闭。最终 dist[3]=2.0,真最优 1.0(0→2→1→3),误差 100% 且毫无报警。

2.1 三层真相:课本版错、堆版侥幸、负环必死

做这个实验时我踩了一脚真实的坑, worth 单独一节。第一版反例图构造不对,堆版 Dijkstra 居然算对了——追查后发现一个课本不讲的三层结构:

  1. 课本版(确定后不再更新):负权边即错。图 1 实测 dist[3]=2.0 vs 真值 1.0;
  2. 允许重访的堆版(dist[v]更小就再入堆、弹出时已过期则跳过):负权边的改进还能传播。87 组含负权的随机图实测全部答对——但这是"意外正确":每次改进都重新入堆,复杂度退化无上界;
  3. 含负环的图:dist 沿负环每绕一圈递减,堆无限膨胀——死循环。调试本讲实验时,一个含负环的随机测试图让程序挂了 8 分钟,进程杀掉才解脱。

所以"Dijkstra 为什么怕负权"的完整答案分三层:课本实现给错答案;堆实现靠重访侥幸给对但复杂度失控;遇到负环则连"答案"这个概念都不存在。三层对应三种工程后果:错误结果、超时、挂死——一层比一层疼。

2.2 对拍:正确性的边界就是"非负"两字

图 2:左:正权随机图 200 组,Dijkstra 与 Bellman-Ford 距离向量零分歧(注意:不连通时双方都是 INF,abs(INF−INF)是 NaN 会悄悄破坏比较——对拍代码必须先做相等性判断,这是本讲调试时踩的第二个坑);右:87 组含负权(无负环)图,堆版全对——但别用它,理由见 2.1 第 3 层。

3. Bellman-Ford:允许"后悔"的算法

课本原话:对所有边做 V−1 轮松弛,任何"晚到的更优解"都有机会传播。第 V 轮仍可松弛 ⟺ 存在负环。

图 3:随机图上 Bellman-Ford 的实际收敛轮数。n=50~400 时均值 5.3~6.7 轮、最大 10 轮——远小于理论上限 V−1(49~399)。红菱形是理论上限,和蓝柱之间隔着一个数量级。

这正是早停的价值:changed标志一置 False 就收工,随机图上几乎总是几轮结束。但复杂度报价仍按最坏 O(VE)——随机图的友好不能当饭吃,第 6 节的横评会看到它最坏时的样子。

3.1 实际轮数远小于 V−1

Bellman-Ford 的另一个身份是负环检测器:第 V 轮仍可松弛 ⟺ 负环存在。第 4 节用 fixture 验证过它的报警功能。

4. 负环检测:两个检测器互相校验

负环一旦存在,"最短路"这个概念就死了(绕一圈便宜一次,可以无限刷)。检测它有两套独立思路:

  • Bellman-Ford:第 V 轮仍能松弛;
  • Floyd:跑完后对角线dist[i][i] < 0。

图 4:负环 fixture(0→1→2→0 总权 −1)。Floyd 的对角线变负([−1, −1, −2]),Bellman-Ford 第 V 轮仍可松弛——两个独立实现的检测器结论一致。检测器本身也要用 fixture 验证"真的会响",这一原则贯穿整个系列。

5. Floyd:三重循环凭什么正确

课本原话:dp[k][i][j]= 只允许经过中转点 {1…k} 时 i 到 j 的最短路;转移dp[k][i][j] = min(dp[k−1][i][j], dp[k−1][i][k] + dp[k−1][k][j]),滚动数组压掉一维就是课本那三重循环。

"k 的含义"是这一节唯一需要真正理解的东西。我们直接把每一轮的 dist 矩阵拍下来:

图 5:n=5 的五联热图。k=1:允许中转 0 号点,部分 ∞ 消失;k=2、k=3 继续改善(红色标题);k=4 一轮无变化(灰色——该点带来的改进已被前面覆盖);k=5 又有改善。每过一轮,图就"解锁"一个新中转点——这就是 k 的全部含义,动态规划的正确性一眼可见。

正确性对拍:Floyd 与逐源 Dijkstra60 组随机图零分歧;next 矩阵重建的路径与 Dijkstra prev 树重建的路径30/30 对总代价一致(第一版对拍只有 7/30——next 更新写成了nxt[k][j],标准写法是nxt[i][k],即"i→k 路径的第一步";一个下标写错,路径重建就废了)。

6. 规模横评:两条 n³ 的曲线与一条 n² 的曲线

图 6:稠密图(m≈n²/4)单源耗时。n=400:Dijkstra 1.84ms、Bellman-Ford 10.03ms、Floyd2155ms。注意口径——Floyd 算的是全源,Dijkstra 只是单源;但即使 n 次 Dijkstra 全源(≈0.7s)也快过 Floyd(2.2s)。Floyd 赢的不是速度,是 10 行代码、是全源一步到位、是免费附赠的负环检测。

图 7:稀疏图(m=6n)上 Dijkstra vs Bellman-Ford。n=800:0.95ms vs 1.95ms——BF 只慢约 2 倍。O(VE) 与 O((n+e)logn) 的理论差距该有几十倍,但 BF 内层是纯数组扫描、堆却是 Python 对象——第 3 篇"复杂度≠性能"的教训在稀疏图上再次应验。

7. 选型元图

图 8:先问四个问题——负权?稠密?全源?负环?依次映射到三件套,负环直接判"不存在"。

8. 本讲检查清单

□ Dijkstra 怕负权的完整答案?(课本版给错答案;堆版靠重访侥幸对但复杂度失控;负环挂死) □ Dijkstra 正确性的前提?(边权非负——200 组正权对拍零分歧) □ Bellman-Ford 实际几轮收敛?(随机图 5~7 轮,但复杂度按 O(VE) 报价) □ 负环怎么查?(BF 第 V 轮仍松弛 / Floyd 对角线变负,两法独立且一致) □ Floyd 的 k 是什么?(只允许中转 {0..k−1} 的最短路——图 5 的五联热图) □ Floyd 的 next 矩阵怎么更新?(nxt[i][j] = nxt[i][k],不是 nxt[k][j]!) □ 稠密/稀疏图怎么选?(稠密单源 Dijkstra;全源看场景——Floyd 代码最短还送负环检测)

9. 复现指南

graph-course/ ├── course4.py # 六组实验(反例/对拍/轮数/k 演化/横评/负环,~330 行) ├── figs4.py # 8 张配图 ├── results/course4.json └── figures/
python course4.py# → results/course4.json(约 2 分钟)python figs4.py# → 8 张图

正确性断言:正权对拍 200 组零分歧(含 INF 相等性兜底);Floyd 与逐源 Dijkstra 60 组零分歧;路径重建双方法 30/30 代价一致;负环 fixture 双检测器一致;负权组先跑 BF 判负环再跑 Dijkstra——顺序不能反,堆版 Dijkstra 遇负环会死循环(8 分钟的教训)。

10. 下一讲预告

第 5 讲《生成树与拓扑排序》:MST 的切割性质用"两半城市的最短桥"实证;Prim 与 Kruskal 的分野比课本说的更细(第 3 篇踩过的 O(V²) 常数坑在这里重演);AOE 网的关键路径——为什么"工期"等于"最长路",以及"关键活动延误一天全项目延误一天"的数学含义。

最短路三件套的正确性各有前提:Dijkstra 要非负权,Bellman-Ford 要无负环,Floyd 要你接受 O(n³)。没有万能算法,只有配得上前提的选择。


系列目录:第 1 讲 基本概念与存储 · 第 2 讲 遍历与连通 · 第 3 讲 欧拉图与哈密顿图 · 第 4 讲 最短路三件套(本篇)· 第 5 讲 生成树与拓扑排序 · 第 6 讲 网络流与匹配

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 12:13:22

PS5工具链整合实战:从环境搭建到自动化验证全流程解析

做 PS5 工具链整合这一块&#xff0c;我踩过的坑不算少。今天想借着“AnyPS5”这个项目代号&#xff0c;把这段时间沉淀下来的经验完整梳理一遍。它不是某个商店里能下载到的一键软件&#xff0c;而是我基于官方开发接入框架&#xff0c;自己搭建的一整套跨平台验证与联调环境。…

作者头像 李华
网站建设 2026/10/11 12:13:09

利用Python打造一个逼真的照片桌面

前言 用 Python 把几张照片拼成一张桌面壁纸&#xff0c;听起来是个「玩具项目」&#xff0c;但真正做出来「看着不假」的人并不多。失败的作品通常有三个特征&#xff1a;图片被拉变形、拼缝两侧的亮度差得像补丁、以及成品分辨率与屏幕对不上而被系统拉伸模糊。 所以「逼真」…

作者头像 李华
网站建设 2026/10/11 12:12:27

AnyPS5:面向PS5平台的跨版本逆向分析工具链解析

项目标题&#xff1a;“AnyPS5”这个名称本身带有强烈的指向性与模糊性并存的特征——它既像一个技术代号&#xff0c;又像一句口号&#xff1b;既暗示兼容性、泛用性&#xff08;“Any”&#xff09;&#xff0c;又锚定在特定硬件生态&#xff08;“PS5”&#xff09;。但问题…

作者头像 李华
网站建设 2026/10/11 12:07:48

造纸厂 AR 设备点检的技术实现路径与数据流设计

在造纸厂引入增强现实&#xff08;AR&#xff09;进行设备点检&#xff0c;核心效果在于将静态的纸质或电子表单转化为动态的、与物理设备实时绑定的可视化作业流&#xff0c;解决了传统巡检中“人到了但没看对”、“看了但没记准”以及“发现问题无法即时闭环”的三大痛点。通…

作者头像 李华
网站建设 2026/10/11 12:07:27

Oracle自定义加密函数实战:绕过DBMS_CRYPTO实现等保合规

简介&#xff1a;这份资源面向 Oracle 数据库开发与运维人员&#xff0c;提供一套自定义加密解密函数&#xff0c;用于解决敏感数据脱敏、加密存储与合规传输问题。包内共 3 个文件&#xff0c;以 2 个 sql 脚本和 1 个 txt 说明为主&#xff0c;压缩包约 5KB&#xff0c;其中 …

作者头像 李华