Floyd 不正确实现方式的正确实现

前几天看到三个日本人发的论文,提到了两个很有意思的结论,在这里想好好回顾一下:

论文

Floyd 算法中,循环变量的顺序决定了运行结果

原算法:

如果是 KIJ 的正确顺序,那么你就可以直接得到正确结果

定理一:

如果是 IKJ 的顺序,那么如果你把这个算法跑两遍,一样可以得到正确结果

存在一组至少需要执行两遍的数据

定理二:

如果是 IJK 的顺序,那么你至多需要跑三遍

而且存在一组可以让程序至少执行三遍才能得到正确结果的数据

其实,抓住 Floyd 算法的本质,可以简明的理解这个结论

Bellman_Ford 一样, Floyd 的算法核心便是松弛操作

即用 \(dis_{i,k},dis_{k,j}\) 去更新 \(dis_{i,j}\) ,记做 \(re(i,j,k)\)

通过观察 Floyd 的运行循环,我们可以发现它遍历了每一个有序三元组 \((i,j,k)\)

同样遍历了有序三元组,为什么不同的循环变量顺序得到了不同的结果呢?

我们不难发现,这是因为在 \(re(i,j,k)\)\(dis_{i,k}\)\(dis_{k,j}\) 的值未正确求出

这跟松弛的顺序有关

IJK 的循环顺序实际上说的是所有的松弛操作按 i 为第一关键字,j 为第二关键字,k 为第三关键字排序

这样我们就可以随时确定两个松弛操作发生的先后顺序(只需要比较三元组大小即可)

这里再说一个重要性质,在基于松弛的算法过程中,任何时刻的 \(dis_{i,j}\) 都不可能小于最终的 \(dis_{i,j}\)

这是因为 \(dis_{i,j}\) 的值永远只会减小

这是说如果 \(dis_{i,k}\)\(dis_{k,j}\) 未被正确求出,那么这次松弛就不可能得到正确答案!

但这同样意味着一旦我们有某一个正确的松弛,即使其它的松弛都是错误的,我们依然可以得到正确的结果!

KIJ 的循环顺序保证了不会有任何一个错误的松弛

但跑多遍 IKJIJK 虽然有错误松弛,但仍然能跑出正确答案

以下的证明的逻辑基础就在于寻找某一个正确的松弛

另一个重要的逻辑是我对于任选的一些点对都可以证明可以得到正确答案,那么最终的整个算法就是正确的

现在着手准备证明定理一

引理一:

对于 IJK 顺序循环

\(path=\{u_1(=s),u_2,u_3\dots u_l(=t)\}\) 是 s 到 t 的任意一条最短路

对于这上面的某个区间 \([a,c]\) 满足 \(\forall b\in[a+1,c-1],u_b<u_a,u_b<u_c\)

则在在最外层循环 \(i=u_a\) 执行后一定能得到正确的 \(dis_{u_a,u_c}\)

引理一证明:

\(path\) 的长度进行归纳

\(path\) 长度不超过三时,\((i,k)(k,j)\) 就是原图中的边,直接松弛

现在假设 \(b=\max_{i\in [a+1,c-1]}u_i\)

则区间 \([u_a,u_b]\) 和区间 \([u_b,u_c]\) 满足归纳条件

\(dis_{u_a,u_b},dis_{u_b,u_c}\) 被正确求出

而且这两个区间中的点的松弛 \(re(u_a,u_b,u_x)\)\(re(u_b,u_c,u_x)\) 显然发生在最后的 \(re(u_a,u_c,u_b)\) 之前

所以能正确求出 \(dis_{u_a,u_c}\)

定理一证明:

在一次循环后,图中多了许多新的边,而且原图的边边权也改变了(这里的“边权”指 \(dis_{i,j}\)

对于原来的 \(path=\{u_1(=s),u_2,u_3\dots u_l(=t)\}\)

运用引理一后,将 \(path\) 分割成满足引理一的一些区间 \([u_{k_1(=1)},u_{k_2}],[u_{k_2},u_{k_3}]\dots[u_{k_{l'-1}},u_{k_{l'}}]\)

得到 \(path'=\{v_1(=s),v_2,v_3\dots v_{l'}(=t)\},path'\in path\)

相邻两项 \(dis\) 被正确求出

不难证明,存在一种分割使得这个路径数组是单峰的,其中最大值是峰顶 (记做 \(v_k\))(只需要不断地找到比第一个左/右端点大的数即可)

由于我们一定在途中添加了长度为最短路的新边 \(dis_{v_1,v_2},dis_{v_2,v_3}\dots dis_{v_{l'-1},v_{l'}}\)

所以我们得到了新的最短路 \(path'\)

再次执行 IJK 程序

对于左边的上升的山坡,我们可以看出来 \(re(v_1,v_3,v_2)\) 发生在 \(re(v_1,v_4,v_3)\) 之前,因此 \(dis_{v_1,v_3}\) 被正确求出后进而正确求出 \(dis_{v_1,v_4}\) ,则 \(dis_{v_1,v_k}\) 被正确求出

同理对右边下降的山坡讨论,\(re(v_{l'-2},v_{l'},v_{l'-1})\) 同样发生在 \(re(v_{l'-3},v_{l'},v_{l'-2})\) 之前,\(dis_{v_k,v_{l'}}\) 被正确求出

执行第三次 IJK 程序,\(re(v_1,v_{l'},v_k)\) 正确求出 \(dis_{s,t}\)

由于综上过程对任意点对 \((s,t)\) 成立,这说明执行三次 IJK 顺序的循环总是能够正确求出 \(dis\) 数组,定理一成立

引理二:

IKJ 的循环顺序中,同样设 \(path\)\((s,t)\) 之间的一条最短路

对于之上的区间 \([a,c]\) 若有 \(\forall b\in [a+1,c-1],u_a>u_b\) ,则在循环 \(i=u_a\) 后,\(dis_{u_a,u_c}\) 会被正确求出

引理二证明:

同样对长度归纳

将原区间分割成若干个子区间 \([a_1(=a),a_2],[a_2,a_3]\dots[a_{len},a_{len+1}(=c)]\) ,满足 \(u_{a_1}<u_{a_2}<\dots<u_{a_{len}}<u_a\),使用归纳假设,则 \(\forall p\in[1,len],dis_{u_{a_p},u_{a_p+1}}\) 被正确求出

依次执行 \(re(u_{a_1},u_{a_3},u_{a_2}),re(u_{a_2},u_{a_4},u_{a_3})\dots re(u_{a_{len-1}},u_{a_{len+1}},u_{a_{len}})\)\(dis_{u_a,u_c}\) 被正确求出

定理二证明:

执行一遍 IKJ 式循环后,不难找到一个 \(path'\in path\) ,使得 \(v_1(=s)<v_2\dots <v_{l'}(=t)\) ,且相邻两项 \(dis\) 被正确求出

再次执行 IKJ 循环后,不难说明 \(dis_{s,t}\) 会被正确求出

定理二证毕

posted @ 2021-11-18 21:01  yyyyxh  阅读(676)  评论(3编辑  收藏  举报