V

算法可视化

ZHEN
分享到微博分享到 XGitHub 仓库个人主页
学习工具算法复杂度速查算法学习路径
数据结构数组链表栈队列树堆哈希表图字典树并查集LRU 缓存跳表线段树B+ 树布隆过滤器树状数组
经典排序算法冒泡排序鸡尾酒排序双调排序选择排序插入排序二分插入排序希尔排序归并排序自顶向下归并快速排序三路快排双轴快排堆排序计数排序基数排序桶排序
图算法Dijkstra 最短路Kruskal 最小生成树Prim 最小生成树Bellman-Ford 最短路拓扑排序Floyd 多源最短路强连通分量2-SAT最大流二分图匹配LCA 倍增欧拉路径
动态规划编辑距离0-1 背包完全背包最长公共子序列最长递增子序列硬币找零方案数石子合并旅行商 TSP树形 DP数位 DP换根 DP
回溯与搜索N 皇后子集生成全排列组合总和迷宫寻路岛屿数量单词搜索数独A* 寻路
字符串KMP 字符串匹配Rabin-KarpBoyer-MooreManacher后缀数组LCP / height 数组AC 自动机Z 函数
数学与数论埃氏筛线性筛欧几里得算法快速幂扩展欧几里得中国剩余定理欧拉函数米勒-拉宾FFTPollard's Rho
计算几何凸包旋转卡壳最近点对线段相交扫描线求交
查找二分查找二分边界旋转数组搜索二分答案三分查找

Floyd-Warshall 多源最短路

图算法 · 全源最短路径(任意两点)

一次求出所有点对的最短路

Dijkstra、Bellman-Ford 都是单源最短路——从一个起点出发。可有时我们想知道 任意两点之间的最短距离(比如任意两城市间的最短车程)。挨个点跑一遍单源当然行,但 Floyd-Warshall 用一张距离矩阵+ 三行循环,优雅地一次算出全部。

Floyd 怎么做

用矩阵 dist[i][j] 存「i 到 j 当前已知的最短距离」,初始就是邻接矩阵(有直接边取边权,没有则 ∞,自己到自己为 0)。然后逐个把每个点 k 试作中转点:对每一对 (i, j),如果「i 先到 k,再从 k 到 j」比「i 直接到 j」更短,就更新 dist[i][j]。三层循环 for k / for i / for j,跑完就得到所有点对的最短距离。

下面固定一张 4 个点的有向带权图。点「下一步」逐步看:每选定一个中转点 k,它所在的行与列高亮;对每个候选单元 (i,j)(琥珀环),比较它与「两个黄色源单元之和」dist[i][k]+dist[k][j]——更短就变绿更新。走到底,矩阵里就是任意两点的最短距离。右侧代码随每一步同步高亮。

ABCD
A036∞
B∞024
C∞∞01
D5∞∞0

距离矩阵初始化为邻接矩阵(对角 0,有边取权,其余 ∞)

1function floyd(adj: number[][], n: number): number[][] {
2 const dist = adj.map((row) => [...row]);
3 for (let k = 0; k < n; k++) {
4 for (let i = 0; i < n; i++) {
5 for (let j = 0; j < n; j++) {
6 if (dist[i][k] + dist[k][j] < dist[i][j]) {
7 dist[i][j] = dist[i][k] + dist[k][j];
8 }
9 }
10 }
11 }
12 return dist;
13}
n4
中转 k-
已更新0
1 / 19

为什么三重循环、k 在最外层就对?这其实是动态规划:做完前 k 个中转点,dist[i][j] 就是「只允许经过前 k 个点中转」的最短路;加入第 k 个点后取 min,逐步放开限制直到允许所有点。复杂度 O(V³)——点少时简单又全面,还能处理负权边(无负环)。

Floyd vs 单源最短路

Dijkstra / Bellman-Ford:单源,一次一个起点;稀疏图上跑 V 次也常更快。
Floyd(本页):全源,一次算出所有点对;O(V³)、代码极短,稠密小图首选,是「矩阵 DP」的经典范例。
Floyd 的距离矩阵思路,正是动态规划在网格上填表的缩影。

想复习单源最短路,回看 Dijkstra 最短路(正权贪心)与 Bellman-Ford 最短路(负权松弛)——三页合起来就是最短路问题的完整版图。