这个是比较容易的。考虑 dp,记 f_{k,i,j} 表示从 i 到 j 只考虑编号不超过 k 的顶点作为中转点时的最短路长度。考虑是否经过顶点 k 则有转移 f_{k,i,j}=\min(f_{k-1,i,j},f_{k-1,i,k}+f_{k-1,k,j})。这个转移的正确性是显然的,滚动一下 k 的维度即可得到普通 Floyd 的实现。而对于固定的 k 交换 i,j 循环顺序显然不会影响正确性。因此 k,i,j 和 k,j,i 都只需要执行一轮即可求出正确的最短路长度。
2. i,k,j 为什么只需要执行两轮
先考虑这样一个关键的结论:对一条从 x 到 y 的最短路而言,若其经过的内部所有点的编号都小于 x,则第一轮处理完 i=x 后 mp_{x,y} 的值一定是正确的。这个结论可以归纳证明:对所有满足条件的最短路 x\to u_1\to u_2\to\ldots\to u_m\to y 其中 \forall u_i<x 从左向右扫描其内部顶点并只保留不断刷新前缀最大值的顶点,记为 v_1<v_2<\ldots<v_r<x 其中 v_1=u_1。观察相邻两个被保留的顶点 v_p,v_{p+1} 因为 v_{p+1} 是第一个超过 v_p 的顶点因此原来路径上这两个顶点之间的所有内部顶点都小于 v_p。最后一段 v_r\to y 同样也满足这个性质。因此根据对起点编号的归纳可知在处理第 x 行之前 mp_{v_p,v_{p+1}} 和 mp_{v_r,y} 的值都全部正确了,因为这些子路径的起点编号都小于 x。
现在考虑处理 i=x。因为 x\to v_1 本来就是一条边,而 k 从小到大枚举因此可以依次进行 x 从 v_1 到 v_2 再到 v_3 以知道 y 的整个流程。每一步需要的前缀距离都已经在前面的 k 中计算完成,而后缀距离则在处理第 x 行之前就已经算对了,因此最后可以得到正确的 mp_{x,y} 值。
现在考虑任意一条从 s 到 t 的最短路 s=u_0\to u_1\to \ldots\to u_m=t 从左往右扫描初始记录的最大编号为 s 之后只保留严格超过此前最大便好的内部顶点。设当前保留的顶点是 s=v_0<v_1<\ldots<v_r(t 不需要满足这个大小关系),则对任意相邻的两个博阿留顶点,原来路径中者之间的内部顶点编号都小于前一个保留的顶点编号,因此根据引理可知第一轮 Floyd 结束后可以将这些子路径分别压缩成一条权值正确的边。也就是说,第一轮 Floyd 之后一定存在一条等长的最短路,满足 s=v_0<v_1<\ldots<v_r\to t。除了 v_r,t 之间以外的最短路相邻结点部分编号一定是严格递增的。
然后考虑第二轮为什么一定可以求出答案,处理 i=s 时因为 k 是从小到大枚举的所以可以沿着刚才得到的路径依次转移 mp_{s,v_2}\leftarrow mp_{s,v_1}+mp_{v_1,v_2},mp_{s,v_3}\leftarrow mp_{s,v_2}+mp_{v_2,v_3},\ldots,mp_{s,t}\leftarrow mp_{s,v_r}+mp_{v_r,t}。这些边的距离在第一轮就已经算对了,因此第二轮一定能够计算出 s\to t 的最短路。因为 s,t 是任意的,可以得出结论,i,k,j 这个顺序重复执行两轮 Floyd 算法一定可以求出任意两个点之间最短路的长度。