说到 Floyd 算法,大多数人的第一反应就是图论中的全源最短路径问题的求解算法,该算法基于动态规划实现,因此要求图的存储结构基于邻接矩阵。关于该算法的细节不再赘述,本文主要总结该算法的延伸应用。
传递闭包
在数学中,在集合 X 上的二元关系 R 的传递闭包是包含 R 在 X 上的最小的传递关系。换言之,在给定的元素集合 X 和若干对 X 上的二元关系,且关系存在传递性,那么通过传递性推导出尽可能多的元素之间的关系的问题就称为传递闭包。
用矩阵元素 f[i, j] = 1 表示 i 与 j 有关系,f[i, j] = 0 表示 i 与 j 之间没有关系,则使用 Floyd 算法可以解决传递闭包的求解问题:
f[i, j] |= f[i, k] & f[k, j]。
【模板】Cow Contest S(USACO 2008)
无向图的最小环
无向图的最小环同样可以基于 Floyd 算法求解,当外层循环 k 刚开始的时候,f[i, j] 保存着“经过编号不超过 k - 1 的顶点”从 i 到 j 的最短路长度,于是 min{f[i, j] + d[i, k] + d[k, j]} 就是满足由编号不超过 k 且经过 k 的顶点构成的最小环长度,其中 1 ≤ i < j < k。那么我们只需要在外层循环刚开始的时候更新一遍答案即可:
ans = min(ans, f[i, j] + d[i, k] + d[k, j])。
【模板】sightseeing trip(CEOI 1999)
内向树的环
内向树是基环树的一种,即该树是有 n 个结点、n 条边、每个结点有且仅有一条出边的有向连通图。
通常我们可以采用 Dijkstra 算法求解,这里介绍另一种算法:Floyd 判圈算法,亦称龟兔赛跑算法,算法流程如下:
- 任选一个点 s 作为起点,设定两个指针 slow(龟)、fast(兔),令 slow = next[s],fast = next[next[s]];
- 让龟兔开始赛跑,其中乌龟一次一步,兔子一次两步,直到龟兔相遇;
- 让兔子原地不动,乌龟继续一次一步,直到龟兔再次相遇,该过程乌龟所走过的顶点构成一个环。
该算法的基本原理基于如下事实:
由于龟兔速度不一致,因此在环路之外两者不可能相遇,而对于内向树,一旦进入环路就出不去,因此两者相遇时必定在环路之上。
如果要求解环路的入口,则将上述第 3 步调整为如下过程:
- 让兔子回到起点 s,然后重新开始赛跑,其中龟兔均一次一步,直到龟兔再次相遇,相遇的地方就是环的入口。
该算法的基本原理基于如下事实:
在第 2 步龟兔相遇时,兔子跑过的路程是乌龟跑过路程的两倍,而且相遇点一定在环上,因此龟兔路程的差值(也就是乌龟走过的路程)是环长的倍数;在第 3 步龟兔又跑过了 k 步两者相遇,此时乌龟走过的路程就是 m * L + k,可以认为乌龟先经过 k 步到达了环的起点(这是兔子从起点 s 跑 k 步到达的位置,也是第二次龟兔相遇的位置),又绕着环跑了 m 圈,则最终必定回到环的起点。
【模板】信息传递(NOIP2015 提高组)