Kosaraju 算法
Kosaraju 算法
一.算法简介
在计算科学中,Kosaraju的算法(又称为–Sharir Kosaraju算法)是一个线性时间(linear time)算法找到的有向图的强连通分量。它利用了一个事实,逆图(与各边方向相同的图形反转, transpose graph)有相同的强连通分量的原始图。
有关强连通分量的介绍在之前Tarjan 算法中:Tarjan Algorithm
逆图(Tranpose Graph ):
我们对逆图定义如下:
GT=(V, ET),ET={(u, v):(v, u)∈E}}
上图是有向图G , 和图G的逆图 GT
摘录维基百科上对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:
- Mark u as visited.
- For each out-neighbour v of u, do Visit(v).
- Prepend u to L.
- Otherwise do nothing.
- If u is unvisited then:
- 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:
- Assign u as belonging to the component whose root is root.
- For each in-neighbour v of u, do Assign(v,root).
- Otherwise do nothing.
- If u has not been assigned to a component then:
通过以上的描述我们发现,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 算法的更多相关文章
- Kosaraju 算法检测有向图的强连通性
给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strong ...
- Kosaraju 算法查找强连通分支
有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v, ...
- 半连通分量--Tarjan/Kosaraju算法
一个有向图称为半连通(Semi-Connected),满足:对于图中任两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. 若满足,则称G’是G的一个导出子图. 若G’是G的导出子图,且G’半 ...
- Kosaraju算法---强联通分量
1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组). 算法描叙: :对 ...
- codevs1506传话(kosaraju算法)
- - - - - - - - 一个()打成[] 看了一晚上..... /* 求强连通分量 kosaraju算法 边表存图 正反构造两个图 跑两边 分别记下入栈顺序 和每个强连通分量的具体信息 */ ...
- Kosaraju算法解析: 求解图的强连通分量
Kosaraju算法解析: 求解图的强连通分量 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 定义 连通分量:在无向图中,即为连 ...
- Kosaraju算法详解
Kosaraju算法是干什么的? Kosaraju算法可以计算出一个有向图的强连通分量 什么是强连通分量? 在一个有向图中如果两个结点(结点v与结点w)在同一个环中(等价于v可通过有向路径到达w,w也 ...
- 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第7章 图 - 有向图强连通分量的Kosaraju算法 ——<数据结构>-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ <数据结构-C语言版>(严 ...
- Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法
一.背景介绍 强连通分量是有向图中的一个子图,在该子图中,所有的节点都可以沿着某条路径访问其他节点.强连通性是一种非常重要的等价抽象,因为它满足 自反性:顶点V和它本身是强连通的 对称性:如果顶点V和 ...
随机推荐
- bt和wifi的共存
转自:http://bbs.52rd.com/Thread-291892-1-1.html 蓝牙和802.11b/g/n都可能工作在2.4GISM,可能互相干扰.干扰的典型应用之一是VOIP,用手机的 ...
- wifi基础知识整理
转自 :http://blog.chinaunix.net/uid-9525959-id-3326047.html WIFI基本知识整理 这里对wifi的802.11协议中比较常见的知识做一个基本的总 ...
- 在多台服务器上简单实现Redis的数据主从复制(3)(转载)
转载地址:http://www.cnblogs.com/liping13599168/archive/2011/04/14/2016226.html Redis的主从复制功能非常强大,一个master ...
- SQLAlchemy增删改查基本操作,及SQL基本技能样码(join,group)
练了一天,基本的东东应该有感觉了. #coding=utf-8 from datetime import datetime from sqlalchemy import (MetaData, Tabl ...
- ArcGIS图层和要素的过滤显示
ArcGIS可以设置动态地图服务(ArcGISDynamicMapServiceLayer)显示哪些图层,也可以设置每个图层根据某个属性字段的某些条件来进行过滤显示. 1.设置显示的图层 主要是通过A ...
- 攻城狮在路上(壹) Hibernate(五)--- 映射一对多关联关系
关联是有方向的,包含单向关联和双向关联.分别讨论.本文以客户Customer和订单Order来进行讨论:一个Customer有多个Order,每个Order对应一个Customer. Customer ...
- android 入门-Eclipse 费解的问题
1.第一次打开eclipse的时候 代码程序出好多红点.等待加载项目,如果加载完项目之后仍然存在,请重启eclipse. 2.如果你在创建页面中的button 的时候,设置了android:gravi ...
- Input对象的type类型
Input表示Form表单中的一种输入对象,其又随Type类型的不同而分文本输入框,密码输入框,单选/复选框,提交/重置按钮等,下面一一介绍. 1,type=text 输入类型是text ...
- document.body.scrollTop
标准浏览器:document.documentElement.scrollTop; 谷歌浏览器:document.body.scrollTop; var scrollTop = document.do ...
- 用JAXP的SAX方式解析XML文件
简单用JAXP的SAX方式(事件驱动)解析XML文件: 文件(1.XML) <?xml version="1.0" encoding="UTF-8" st ...