byvoid 神牛的tarjan算法讲解!

[有向图强连通分量]

在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通 (strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图 。非强连通图有向图的极大强连通子图,称为强连通分量 (strongly connected components)。

下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。

image

直接根据定义,用双向遍历取交集的方法求强连通分量,时间复杂度为O(N^2+M)。更好的方法是Kosaraju算法或Tarjan算法,两者的时间复杂度都是O(N+M)。本文介绍的是Tarjan算法。

[Tarjan算法]

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树 。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。由定义可以得出,

Low(u)=Min { DFN(u), Low(v),(u,v)为树枝边,u为v的父节点 DFN(v),(u,v)为指向栈中节点的后向边(非横叉边) }

当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

算法伪代码如下:

tarjan(u) { DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值 Stack.push(u) // 将节点u压入栈中 for each (u, v) in E // 枚举每一条边 if (v is not visted) // 如果节点v未被访问过 tarjan(v) // 继续向下找 Low[u] = min(Low[u], Low[v]) else if (v in S) // 如果节点v还在栈内 Low[u] = min(Low[u], DFN[v]) if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根 repeat v = S.pop // 将v退栈,为该强连通分量中一个顶点 print v until (u== v) }

接下来是对算法流程的演示。

从节点1开始DFS,把遍历到的节点加入栈中。搜索到节点u=6时,DFN[6]=LOW[6],找到了一个强连通分量。退栈到u=v为止,{6}为一个强连通分量。

image

返回节点5,发现DFN[5]=LOW[5],退栈后{5}为一个强连通分量。

image

返回节点3,继续搜索到节点4,把4加入堆栈。发现节点4向节点1有后向边,节点1还在栈中,所以LOW[4]=1。节点6已经出栈,(4,6)是横叉边,返回3,(3,4)为树枝边,所以LOW[3]=LOW[4]=1。

image

继续回到节点1,最后访问节点2。访问边(2,4),4还在栈中,所以LOW[2]=DFN[4]=5。返回1后,发现DFN[1]=LOW[1],把栈中节点全部取出,组成一个连通分量{1,3,4,2}。

image

至此,算法结束。经过该算法,求出了图中全部的三个强连通分量{1,3,4,2},{5},{6}。

可以发现,运行Tarjan算法的过程中,每个顶点都被访问了一次,且只进出了一次堆栈,每条边也只被访问了一次,所以该算法的时间复杂度为O(N+M)。

求有向图的强连通分量还有一个强有力的算法,为Kosaraju算法。Kosaraju是基于对有向图及其逆图两次DFS的方法,其时间复杂度也是 O(N+M)。与Trajan算法相比,Kosaraju算法可能会稍微更直观一些。但是Tarjan只用对原图进行一次DFS,不用建立逆图,更简洁。 在实际的测试中,Tarjan算法的运行效率也比Kosaraju算法高30%左右。此外,该Tarjan算法与求无向图的双连通分量(割点、桥)的Tarjan算法 也有着很深的联系。学习该Tarjan算法,也有助于深入理解求双连通分量的Tarjan算法,两者可以类比、组合理解。

求有向图的强连通分量的Tarjan算法是以其发明者Robert Tarjan 命名的。Robert Tarjan还发明了求双连通分量 的Tarjan算法,以及求最近公共祖先的离线Tarjan算法,在此对Tarjan表示崇高的敬意。

附:tarjan算法的C++程序

void tarjan(int i) { int j; DFN[i]=LOW[i]=++Dindex; instack[i]=true; Stap[++Stop]=i; for (edge *e=V[i];e;e=e->next) { j=e->t; if (!DFN[j]) { tarjan(j); if (LOW[j]<LOW[i]) LOW[i]=LOW[j]; } else if (instack[j] && DFN[j]<LOW[i]) LOW[i]=DFN[j]; } if (DFN[i]==LOW[i]) { Bcnt++; do { j=Stap[Stop--]; instack[j]=false; Belong[j]=Bcnt; } while (j!=i); } } void solve() { int i; Stop=Bcnt=Dindex=0; memset(DFN,0,sizeof(DFN)); for (i=1;i<=N;i++) if (!DFN[i]) tarjan(i); }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Linux下快速搭建LAMP开发平台.doc

1.安装环境操作系统&#xff1a;Red Hat Linux Enterprise AS 4.0 update4数据库&#xff1a;MySQL 5.0.27Web服务器&#xff1a;Apache 2.2.4脚本语言&#xff1a;PHP 5.2.1<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />2.安…

关于NLP你还不会却必须要学会的事儿—NLP实践教程指南第一编

作者 | Dipanjan (DJ) Sarkar 编译 | 姗姗 出品 | 人工智能头条&#xff08;公众号ID&#xff1a;AI_Thinker&#xff09; 【人工智能头条导读】在研究和处理自然语言处理的很多问题时&#xff0c;除了关注各种各样基础的数据&#xff0c;高级的深度学习模型、算法外&#x…

ORACLE中表死锁的处理

在进行数据库管理的过程中,经常会出现数据表被用户的一些不合理操作而导致表被锁定的情况,以下主要介绍如何查找哪些表被哪个用户所锁定,以及如何解除锁定: 1.查找被锁定的表: select object_name,session_id,os_user_name,oracle_username,process,locked_mode,status from v$…

记录重要的NLP学习资源链接

整理一些NLP学习资源(不止NLP&#xff0c;本人主要关注NLP)&#xff0c;如果有更好的&#xff0c;欢迎分享_ NLP 中文自然语言处理相关资料 https://github.com/crownpku/Awesome-Chinese-NLP Contents 列表 Chinese NLP Toolkits 中文NLP工具 Toolkits 综合NLP工具包 Pop…

asp.net文件上传进度条控件(破解版~没有时间限制) 多项自定义

原版只能用30天&#xff0c;这个破解版可以长期用了&#xff08;设置了时间2010-2110&#xff09;. 注册控件&#xff1a;<% Register TagPrefix"fup" Namespace"OboutInc.FileUpload" Assembly"FileUpload" %>调用控件&#xff1a;<fo…

2010年开年的一地鸡毛

2010年开年的一地鸡毛文 小刀马2010年的网络开年一点儿也不顺利&#xff0c;刚刚半月有余&#xff0c;就接连爆发出两个大事。一是百度被黑&#xff0c;李彦宏惊叹地连说史无前例&#xff0c;史无前例。二是谷歌的退出。两大互联网搜索巨头接连“出事”&#xff0c;不知道是不是…

Java中的向下转型与向上转型

java转型问题其实并不复杂&#xff0c;只要记住一句话&#xff1a;父类引用指向子类对象。 什么叫父类引用指向子类对象&#xff0c;且听我慢慢道来. 从2个名词开始说起&#xff1a;向上转型(upcasting)、向下转型(downcasting). 举个例子&#xff1a;有2个类&#xff0c;Fathe…

细粒度审计 FGA

传统的 Oracle 数据库审计选件允许您在宏观级别上跟踪用户在对象上所执行的操作 — 例如&#xff0c;如果您审计对某个表的 SELECT 语句&#xff0c;则可以跟踪是谁从表中选择了数据。但是&#xff0c;您不知道他们选择了什么。利用数据操纵语句 — 如 INSERT、UPDATE 或 DELET…

矩阵连乘问题的算法分析

问题描述&#xff1a;给定n个矩阵&#xff1a;A1,A2,...,An&#xff0c;其中Ai与Ai1是可乘的&#xff0c;i1&#xff0c;2...&#xff0c;n-1。确定计算矩阵连乘积的计算次序&#xff0c;使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模&…

等一分钟看了会流泪

转载于:https://blog.51cto.com/hljheiwangwei/269127

Silverlight 解谜游戏 之十六 消失的蒙娜丽莎

在《Silverlight 解谜游戏 之三 消除名单》中我们通过在物品轮廓画出Path 来达到消除物品的效果&#xff0c;由于游戏中的物品都是Office 图片的一部分所以无法使其真正消失&#xff0c;本篇我们将添加一个独立于Office 图片的物品&#xff0c;使其能动态消失。 看看题板上多出…

明令禁止工作“996”,是对“生而为人”的基本尊重

离GitHub上996.ICU项目的发布时间已过去好一段时间了&#xff0c;作为一名计算机专业的在读生&#xff0c;对996有一点体会&#xff0c;最直观的体会就是为了提升技术&#xff0c;连续一个学期在实验室工作超过10个小时。 人民日报发文《被“996”围困的年轻人&#xff0c;像是…

ASP.NET教程5

添加方法&#xff0c;在Sql Server创建表&#xff0c;主表与外键表关联&#xff0c;在asp.net中如何绑定下拉式选单DropDownList&#xff0c;并如何重构DropDownList Web控件&#xff0c;创建SELECT与Insert存储过程&#xff0c;以及应用Transaction事务。 文件格式&#xff1a…

火柴 UVa11375

1.题目描述&#xff1a;点击打开链接 2.解题思路&#xff1a;本题利用递推关系解决。首先可以把“已经使用过的火柴数i”看做状态&#xff0c;可以得到一个图&#xff0c;从前往后每添加一个数字x&#xff0c;就从状态i转移到了ic[x]&#xff0c;其中c[x]代表数字x需要的火柴数…

EntitySpaces2009的开发文档地址

EntitySpaces2009的开发文档地址&#xff0c;开发文档做得还是很不错的&#xff0c;主要的和关键的问题都在其中说明了&#xff0c;比示例做得好。 http://developer.entityspaces.net/documentation/Default.aspx转载于:https://www.cnblogs.com/Rising/archive/2010/01/31/16…

ACM 博弈专题(5种模板)

最近算法课在学博弈论的知识&#xff0c;顺手把算法题中的涉及到博弈论一并总结了 这篇文章的有些内容是参考了大佬的 可能有遗漏。。。。 (一)巴什博弈&#xff08;BAsh Game) 题目模板 只有一堆n个物品两个人轮流取&#xff0c;每次只能取1~m个物品&#xff0c;谁先取完&am…

让sky Driver成为你的可见硬盘

网盘就不用多说了&#xff0c;国内国外的都很多&#xff0c;但是sky Driver以25G的大容量还是吸引着我&#xff0c;看来还是盖茨比较称钱&#xff08;sorry&#xff0c;方言&#xff0c;意思就是nb的意思&#xff09;&#xff0c;但是一向以用户体验非常不错著称的microsoft在这…

初学博弈论

一、巴什博奕(Bash Game) 基本描述&#xff1a; 只有一堆n个石子&#xff0c;两个人轮流从这堆石子中取石子&#xff0c;规定每次至少取一个&#xff0c;最多取m个&#xff0c;最后取完的人获胜。 分析&#xff1a; 当n < m的时候&#xff0c;显然先手获胜&#xff0c;因…

设计模式----Adapter(适配器)

作用: 将一个类的接口转换成客户希望的另外一个接口。Adapt 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 UML示意图 1)采用继承原有接口类的方式 2)采用组合原有接口类的方式 解析: Adapt模式其实就是把完成同样的一个功能但是接口不能兼容的类桥接在一起…

浅谈算法——博弈论

注&#xff1a;下列游戏都建立在双方都有最优策略的情况下&#xff0c;若未加以说明&#xff0c;则每人每次至少取一个石子。 例1&#xff1a;取石子游戏之一 有两个游戏者&#xff1a;A和B。有n颗石子。 约定&#xff1a;两人轮流取走石子&#xff0c;每次可取1、2或3颗。A先…