• Kosaraju算法


    Kosaraju算法也许最容易理解的一个算法是Kosaraju于80年代提出的,它执行两次DFS。第一次DFS得到了关于各个SCC拓扑顺序的有关信息,而第二次DFS按照这个拓扑顺序的逆序进行DFS,从而把每个SCC分开。
    算法步骤如下:第一步调用(DFS(G)),计算出每个结点的(f[u])或者(post[u])第二步计算G的转置GT (即把所有有向边(u, v)变为有向边(v, u))第三步调用(DFS(GT )),在主循环中按照(f[u])或者(post[u])递减的顺序执行DFS-VISIT,则得到的每个DFS树恰好对于一个SCC。
    算法的时间复杂度为(O(n+m)),但注意并不是在图的所有表示法中都很容易求出转置。
    为什么算法是正确的呢?
    我们首先证明以下定理:
    定理:(d(U))(f(U))表示集合U所有元素的最早发现时间和最晚完成时间,则对于G中的两个SCC C和C',如果C到C'有边,则(f(C)>f(C'))。证明分两种情况。
    情况一:(d(C)<d(C'))。考虑C中第一个被发现的点(x),则(x)被发现时(C')全为白色。而(C)(C')有边,故(x)(C')中的每个点都有白色路径。这样,(C)的其他点和(C')的所有点都是x的后代,因此(f(C) > f(C'))
    情况二:(d(C)>d(C'))。由于从(C')不可到达(C),所以必须等(C')全部访问完毕后才能访问(C),因此(f(C) > f(C'))。作为定理的推论,如果GT 中(C)(C')有边,则(f(C)<f(C'))。由于G和GT 的强连通分量完全一致,所以只需要在GT 中按照(f)值递减的顺序执行DFS-VISIT即可。可能有读者会认为不需要转置而直接在G中按照f递增的顺序执行DFS-VISIT也能奏效,但可惜这是错误的。对于G中的两个SCC (C)(C'),如果C到(C')有边,刚才的定理说的是(f(C)>f(C')),其中二者取的是(C)(C')(f)值的最大值,而并没有说(C)(C')中最小的f值哪个大。如果按照f递增的顺序遍历,我们无法知道究竟会先遇到(C)中的点还是(C')中的点。如果在GT 上操作,由推论知(f(C)<f(C')),所以当按(f)值降序考虑时一定会先遇到(C')中的点,从而正确的把(C)(C')分开。

  • 相关阅读:
    Flink基础(57):FLINK-SQL函数(20) 内置函数(15)日期函数(二)
    Flink基础(56):FLINK-SQL函数(19)内置函数(14)字符串函数(五)
    位示图算法实现大数据的存储
    位示图算法实现大数据的存储
    JobTracker作业启动过程分析
    mysql 查询优化~ 分页优化讲解
    mysql 原理~ index的详解
    指纹识别开发1.0
    java8 base64编码和解码
    Cow Bowling POJ
  • 原文地址:https://www.cnblogs.com/Douglas-Zhou/p/Kosaraju.html
Copyright © 2020-2023  润新知