Kosaraju 算法

一.算法简介

在计算科学中,Kosaraju的算法(又称为–Sharir Kosaraju算法)是一个线性时间(linear time)算法找到的有向图的强连通分量。它利用了一个事实,逆图(与各边方向相同的图形反转, transpose graph)有相同的强连通分量的原始图。

有关强连通分量的介绍在之前Tarjan 算法中:Tarjan Algorithm

逆图(Tranpose Graph ):

我们对逆图定义如下:

GT=(V, ET),ET={(u, v):(v, u)∈E}}

上图是有向图G , 和图G的逆图 G

摘录维基百科上对Kosaraju Algorithm 的描述:

(取自https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm)

  • For each vertex u of the graph, mark u as unvisited. Let L be empty.
  • For each vertex u of the graph do Visit(u), where Visit(u) is the recursive subroutine:
    If u is unvisited then:
    1. Mark u as visited.
    2. For each out-neighbour v of u, do Visit(v).
    3. Prepend u to L.
    Otherwise do nothing.
  • For each element u of L in order, do Assign(u,u) where Assign(u,root) is the recursive subroutine:
    If u has not been assigned to a component then:
    1. Assign u as belonging to the component whose root is root.
    2. For each in-neighbour v of u, do Assign(v,root).
    Otherwise do nothing.

通过以上的描述我们发现,Kosaraju 算法就是分别对原图G 和它的逆图 GT 进行两遍DFS,即:

1).对原图G进行深度优先搜索,找出每个节点的完成时间(时间戳)

2).选择完成时间较大的节点开始,对逆图GT 搜索,能够到达的点构成一个强连通分量

3).如果所有节点未被遍历,重复2). ,否则算法结束;

二.算法图示

上图是对图G,进行一遍DFS的结果,每个节点有两个时间戳,即节点的发现时间u.d和完成时间u.f

我们将完成时间较大的,按大小加入堆栈

1)每次从栈顶取出元素

2)检查是否被访问过

3)若没被访问过,以该点为起点,对逆图进行深度优先遍历

4)否则返回第一步,直到栈空为止

[ATTENTION] : 对逆图搜索时,从一个节点开始能搜索到的最大区块就是该点所在的强连通分量。

从节点1出发,能走到  2 ,3,4 , 所以{1 , 2 , 3 , 4 }是一个强连通分量

从节点5出发,无路可走,所以{ 5 }是一个强连通分量

从节点6出发,无路可走,所以{ 6 }是一个强连通分量

自此Kosaraju Algorithm完毕,这个算法只需要两遍DFS即可,是一个比较易懂的求强连通分量的算法。

STRONG-CONNECTED-COMPONENTS ( GRAPH G )
1 call DFS(G) to compute finishing times u.f for each vertex u
2 compute GT
3 call DFS (GT) , but in the main loop of DFS , consider the vertices
         in order of decreasing u.f ( as computed in line 1 )
4 output the vertices of each tree in the depth-first forest formed in line 3 as a
         separate strongly-connected-componet

三.算法复杂度

邻接表:O(V+E)

邻接矩阵:O(V2)

该算法在实际操作中要比Tarjan算法要慢

四.算法模板&注释代码

 #include "cstdio"
#include "iostream"
#include "algorithm" using namespace std ; const int maxN = , maxM = ; struct Kosaraju { int to , next ; } ; Kosaraju E[ ][ maxM ] ;
bool vis[ maxN ];
int head[ ][ maxN ] , cnt[ ] , ord[maxN] , size[maxN] ,color[ maxN ]; int tot , dfs_num , col_num , N , M ; void Add_Edge( int x , int y , int _ ){//建图
E[ _ ][ ++cnt[ _ ] ].to = y ;
E[ _ ][ cnt[ _ ] ].next = head[ _ ][ x ] ;
head[ _ ][ x ] = cnt[ _ ] ;
} void DFS_1 ( int x , int _ ){
dfs_num ++ ;//发现时间
vis[ x ] = true ;
for ( int i = head[ _ ][ x ] ; i ; i = E[ _ ][ i ].next ) {
int temp = E[ _ ][ i ].to;
if(vis[ temp ] == false) DFS_1 ( temp , _ ) ;
}
ord[(N<<) + - (++dfs_num) ] = x ;//完成时间加入栈
} void DFS_2 ( int x , int _ ){
size[ tot ]++ ;// 强连通分量的大小
vis[ x ] = false ;
color[ x ] = col_num ;//染色
for ( int i=head[ _ ][ x ] ; i ; i = E[ _ ][ i ].next ) {
int temp = E[ _ ][ i ].to;
if(vis[temp] == true) DFS_2(temp , _);
}
} int main ( ){
scanf("%d %d" , &N , &M );
for ( int i= ; i<=M ; ++i ){
int _x , _y ;
scanf("%d %d" , &_x , &_y ) ;
Add_Edge( _x , _y , ) ;//原图的邻接表
Add_Edge( _y , _x , ) ;//逆图的邻接表
}
for ( int i= ; i<=N ; ++i )
if ( vis[ i ]==false )
DFS_1 ( i , ) ;//原图的DFS for ( int i = ; i<=( N << ) ; ++i ) {
if( ord[ i ]!= && vis[ ord[ i ] ] ){
tot ++ ; //强连通分量的个数
col_num ++ ;//染色的颜色
DFS_2 ( ord[ i ] , ) ;
}
} for ( int i= ; i<=tot ; ++i )
printf ("%d ",size[ i ]);
putchar ('\n');
for ( int i= ; i<=N ; ++i )
printf ("%d ",color[ i ]);
return ;
}

2016-09-18 00:16:19

(完)

Kosaraju 算法的更多相关文章

  1. Kosaraju 算法检测有向图的强连通性

    给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strong ...

  2. Kosaraju 算法查找强连通分支

    有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v, ...

  3. 半连通分量--Tarjan/Kosaraju算法

    一个有向图称为半连通(Semi-Connected),满足:对于图中任两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. 若满足,则称G’是G的一个导出子图. 若G’是G的导出子图,且G’半 ...

  4. Kosaraju算法---强联通分量

    1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组).      算法描叙: :对 ...

  5. codevs1506传话(kosaraju算法)

    - - - - - - - - 一个()打成[] 看了一晚上..... /* 求强连通分量 kosaraju算法 边表存图 正反构造两个图 跑两边 分别记下入栈顺序 和每个强连通分量的具体信息 */ ...

  6. Kosaraju算法解析: 求解图的强连通分量

    Kosaraju算法解析: 求解图的强连通分量 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 定义 连通分量:在无向图中,即为连 ...

  7. Kosaraju算法详解

    Kosaraju算法是干什么的? Kosaraju算法可以计算出一个有向图的强连通分量 什么是强连通分量? 在一个有向图中如果两个结点(结点v与结点w)在同一个环中(等价于v可通过有向路径到达w,w也 ...

  8. 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第7章  图 - 有向图强连通分量的Kosaraju算法 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接☛☛☛ <数据结构-C语言版>(严 ...

  9. Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法

    一.背景介绍 强连通分量是有向图中的一个子图,在该子图中,所有的节点都可以沿着某条路径访问其他节点.强连通性是一种非常重要的等价抽象,因为它满足 自反性:顶点V和它本身是强连通的 对称性:如果顶点V和 ...

随机推荐

  1. 菜鸟学Linux命令:端口查看和操作命令

    >>端口和进程 端口不是独立存在的,它是依附于进程的.某个进程开启,那么它对应的端口就开启了,进程关闭,则该端口也就关闭了.下次若某个进程再次开启,则相应的端口也再次开启. >> ...

  2. Validform 学习笔记---基础知识整理

    面对表单的验证,自己写大量的js毕竟不是一个明智的做法.不仅仅是代码很长而且不便于梳理.Validform就是一款开源的第三方验证js的控件,通过添加相应的js以及css能够有效的验证表单,维护起来也 ...

  3. python实现支持并发、断点续传的Ftp程序

    一.要求 1.用户md5认证 2.支持多用户同时登陆(并发) 3.进入用户的命令行模式,支持cd切换目录,ls查看目录子文件 4.执行命令(ipconfig) 5.传输文件: a.支持断点续传 b.传 ...

  4. codeforce好地方啊 Bear and Elections *

    Codeforces Round #318 居然可以看测试数据,哪里没过一目了然,哈哈哈 #include<cstdio> #include<iostream> #includ ...

  5. MongoDB学习(2)—Node.js与MongoDB的基本连接示例

    前提 已经安装了node.js和MongoDB,本文使用的node.js是v0.12.0,MongoDB是3.0.0. 初始化数据 启动MongoDB服务,在test数据库中插入一条实例数据: db. ...

  6. .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱

    为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...

  7. Salesforce中所有常用类型字段的取值与赋值

    Salesforce中所有常用字段类型的定义以及如何用代码进行取值和赋值: Field Type的定义: http://www.salesforce.com/us/developer/docs/api ...

  8. UVA 12901 Refraction 数学

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83008#problem/E Description HINT 题意: 给你一个 ...

  9. MATLAB中stem函数用法

    stem(Y) 将数据序列Y从x轴到数据值按照茎状形式画出,以圆圈终止.如果Y是一个矩阵,则将其每一列按照分隔方式画出. stem(X,Y)在X的指定点处画出数据序列Y.  stem(...,'fil ...

  10. 出来ios顶部导航掉下来问题

    <script type="text/javascript"> setposition(); function setposition(){ var ua = navi ...