算法作用
求给定图中任意两点间的最短距离
时间复杂度
O(v^3) V是顶点个数
代码实现(3个for)
g是用邻接矩阵传入的图, 如果两点之间没有路径, 设成inf, 否则设成边权, n是顶点个数, 顶点编号默认0~n-1, 最后i, j点的最短路径在g[i][j]中
void floyd(int g[][], int n) {
for(int k = 0; k < n; ++k)
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
算法拓展
可用用floyd判环g[i][j]表示i, j之间有路, 如果g[i][j] = 1 并且g[j][i]=1 那么i, j之间有环, 同时取最小值应该改成二进制的或运算
算法证明
根本思想方法来自动态规划;
假设现在已经有了从i到j的最短路, 那么有两种情况:
为方便证明给出图例
图1. floyd简单证明图
可以知道i到j的最短路是i->k1->k2->k3->j
那么直接给出转移方程g[i][j] = min(g[i][j], g[i][k] + g[k][j]) 代表的意思是g[i][j]之间的最短路等于
1. 本来i到j的距离
2. i 经过一个中间点k再到j
这些路中取最小
意思也很好理解: i到j的最短距离要么是i到j的本来就有的距离(上图的100的边权) 要么先从i到k求到最短距离, 然后再从k到j找到最短距离, 两者加起来即可
代码实现的具体过程及思路
一个一个的加点, 直到加完所有点
比如本来有了图g
1. 加入0号点, 那么图g中和0有关的可以互相到达的两点的最短路径就找出来了
2. 加入1号点, …..
3. 加入2号点, …..
……
为什么能实现呢?
比如在第三步中的加入2号点,
1. 任意两个点的最短路径如果和2号点有关, 那么最短路径一定是g[i][2] + g[2][j], 而在前面的步骤中我已经求出了g[i][2] 和g[2][i], 所以在取min的过程中更新了g[i][j]
2. 如果和2号点无关, 那么g[i][j]一定在是前面求出的最小步骤
举个例子:
加入求1 到 4 的最短路径: 假设是1 –> 3 –> 0 –> 4
1. 加入0点, 那么我就求出了3到4的最短路径也就是3 –> 0 –> 4这条路
2. 加入1点, 由于是这条路的起点, 所以其实他是不变的, 也可以理解成它求出了1–>这条路
3. 加入2点, 由于这条最短路不包含2点, 所以对这条路没有影响
4. 加入3点, 求出1到4的最短路径, 因为在前面已经求出了1–>3的最短路径和3 –> 4的最短路径, 所以这里的min操作就可以取到1 –> 3 –> 0 –> 4这条路径了
……
如此下去, 只要取完所有的n个点, 就求出了解了, 动态规划思想好的应该更容易理解这些……
复杂度证明
明显的3重循环 所以复杂度是O(v^3) v是顶点个数