zoukankan      html  css  js  c++  java
  • 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')分开。

  • 相关阅读:
    css3 font-face
    快速理解RequireJs
    移动HTML5前端性能优化指南
    HTML中head头结构
    JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模)
    巧妙使用CSS媒体查询(Media Queries)和JavaScript判断浏览器设备类型的好方法
    关于浏览器内核与javascript引擎的一些小知识
    SVG 与 Canvas:如何选择
    NodeJS、NPM安装配置步骤(windows版本)
    ie10 css hack 条件注释等兼容方式整理
  • 原文地址:https://www.cnblogs.com/Douglas-Zhou/p/Kosaraju.html
Copyright © 2011-2022 走看看