Warshall’s Algorithm: Transitive Closure小理解

前言

这一算法相关的博客很少,因此我觉得很有必要写这篇博客。但由于我是用网上搜集得来的资料自学的,因此在下面的讲述中可能会有不对的地方,还请dalao们耐心指出,十分感谢。

你最好已经知道的知识:floyd算法,矩阵快速幂。
提前说一下,这个算法和floyd很像,但有新的东西。

我会列举2种我查到的Transitive Closure算法,并对他们进行分析,请读者耐心阅读。

概念

Transitive Closure翻译为“传递闭包”,它到底是什么?参考一下传递闭包(百度百科)

用我的话说,它就是在一个有向图中,所有的「能不能从一个点到另一个点」的关系(老外说得好: all paths in a directed graph)。

举个例子:
图1
[图1:有向图]
(本篇博客所有图片均截自参考资料[1])

那么它的传递闭包是:
图2
[图2:有向图的传递闭包]

图2中实线是原图中的关系,虚线是添加的关系。

有人可能会问,求「是否能到达」算什么,用Floyd算法连最短路都求出来了。确实,「法1」我自认为完全可以用floyd代替,而「法2」则与矩阵运算结合。

法1

我们先思考这个问题,能从u到v的条件:

  1. 存在一条边为 u->v
  2. 存在一个点k,满足 u->k,k->v
  3. 存在中间点k1,k2…kn,满足u->k1,k1->k2,…,kn->v

如何实现这个过程呢?

我们将图1用01矩阵表示(0代表不连通,1代表连通)
图3
[图3:01矩阵]

我们将这个矩阵称之为R。先枚举中间点k,把以k为中间点的路全部找出,找的过程是枚举起点u和终点v,看是否u->k并且k->v,即R[u][k]&&R[k][v],不要忘了原本R[u][v]=1的情况。

for(int k=1; k<=n; ++k)
    for(int u=1; u<=n; ++u)
        for(int v=1; v<=n; ++v)
            R[u][v]|=R[u][k]&R[k][v];

特别注意,k、u、v顺序不可改变。

时间复杂度O(n3),空间复杂度O(n2)。

法2

依然采用上述寻找中间点的思路。我们将这个问题换一个描述方式:在一个有向图中,能不能经过有限条边从u到v。

结合这个描述,「法1」中的矩阵R表示在经过1条边时任意两个点的连通情况(若不存在自环,此时无法到达自己本身)。相应地,我们定义Rk为经过k条边能到达的点的情况(k>=1)。

然后,我们惊喜地发现:Rk = Rk-1 · R。只不过要相应地改变运算,把「乘」换为「并」,把「加」换为「或」。

继续分析,若u->v,则他们最多经过n-2个点,n-1条边。也就是,答案是Rn-1

矩阵运算复杂度n3,n次相乘可以用矩阵快速幂(不懂请百度),复杂度logn。该算法时间复杂度O(n3logn),空间复杂度O(n2)。

但这样的话,「法2」还不如「法1」喽?没事,我们可以改题啊!如果将题目改为:在经过最多k条边时,能不能从u到v,其中k>0。这个问题用「法2」再合适不过了吧!

参考资料

[1].一张pdf
[2]一篇繁体博客

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值