图论 求有向图的所有强连通分量 kosaraju算法

2024-09-03 09:08

本文主要是介绍图论 求有向图的所有强连通分量 kosaraju算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、问题

如何找到有向图(a)中的所有强连通分量,如图(b)

 

 二、kosaraju算法

Kosaraju的算法(又称为–Sharir Kosaraju算法)是一个线性时间(linear time)算法找到的有向图的强连通分量。

 

1. 原理

它利用了一个事实,逆图(与各边方向相同的图形反转, transpose graph)有相同的强连通分量的原始图。

 

2. 逆图

将各边的方向反转

 

3. 算法图示

上图是对图G,进行一遍DFS(深度优先搜索)的结果,

  • 1、2、4、6
  • 1、3、5

 

每个节点有两个时间戳,即节点的

  • 发现时间u.d(左边,即搜索发现的时间)
  • 完成时间u.f(右边,即搜索返回的时间)

 

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

1)每次从栈顶取出元素

2)检查是否被访问过

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

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

 

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

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

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

 

4. 算法复杂度

邻接表:O(V+E)

邻接矩阵:O(V^2)

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

 

5. 算法模板&注释代码

#include "cstdio"
#include "iostream"
#include "algorithm"using namespace std ;const int maxN = 10010 , maxM = 50010;struct Kosaraju { int to , next ; } ;Kosaraju E[ 2 ][ maxM ] ;
bool vis[ maxN ];
int head[ 2 ][ maxN ] , cnt[ 2 ] , 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<<1) + 1 - (++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=1 ; i<=M ; ++i ){int _x , _y ;scanf("%d %d" , &_x , &_y ) ;Add_Edge( _x , _y , 0 ) ;//原图的邻接表Add_Edge( _y , _x , 1 ) ;//逆图的邻接表}for ( int i=1 ; i<=N ; ++i )if ( vis[ i ]==false )DFS_1 ( i , 0 ) ;//原图的DFSfor ( int i = 1 ; i<=( N << 1) ; ++i ) {if( ord[ i ]!=0 && vis[ ord[ i ] ] ){tot ++ ; //强连通分量的个数col_num ++ ;//染色的颜色DFS_2 ( ord[ i ] , 1 ) ;}}for ( int i=1 ; i<=tot ; ++i )printf ("%d ",size[ i ]);putchar ('\n');for ( int i=1 ; i<=N ; ++i )printf ("%d ",color[ i ]);return 0;
}

 

https://www.cnblogs.com/shadowland/p/5876307.html

 

 

 

 

 

这篇关于图论 求有向图的所有强连通分量 kosaraju算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1132591

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W