Tarjan算法初步
一、前置知识:
   强连通分量:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大(看清是极大,不是最大)强连通子图,称为强连通分量(strongly connected components)。一个点x,若没有点与它强连通,则它自己也是一个强连通分量。
二、算法简述
Tarjan算法是一个主要用于求有向图的强连通分量或无向图的环的算法。(当然也有很多扩展,与其他一些神奇的算法搭配可能会碰撞出奇妙的火花)
(无向图的极大连通子图就不叫强连通分量了,叫连通分量。实际上求无向图的连通分量用bfs就行了(毕竟无向图没有方向,只要能到达,就是连通,也没有强连通这一说))
三、原理:
想象一个情景:从一个点u出发,一直向下遍历,然后忽得找到一个点,那个点x竟然有条指回点u的边!
那么想必这个点u能够从自身出发再回到自身
想必这个点u和其他向下遍历的该路径上的所有点构成了一个环,
想必这个环上的所有点都是强联通的。
但只是强联通啊,我们需要求的可是强连通分量啊......怎么在退回到这个点的时候,知道所有和这个点u构成强连通分量的点呢?
开个栈记录就行了。我们建一个栈,保证回溯到u时栈中u及u上面的点组成一个强连通分量,然后把它们弹出、记录就好了。
似乎做法已经明了了,用程序应该怎么实现呢?
四、程序实现:
首先需要介绍一些辅助数组
(1)、dfn[ ],表示这个点在dfs时是第几个被搜到的。
(2)、low[ ],表示这个点以及其子孙节点连的这个点及其祖先中dfn最小的值
(3)、stack[ ],表示当前所有可能能构成强连通分量的点。
(4)、vis[ ],表示一个点是否在stack[ ]数组中。
那么按照之上的思路,我们来考虑这几个数组的用处以及算法的具体过程。
假设现在开始遍历点u:
首先初始化dfn[u]=low[u]=第几个被dfs到
dfn可以理解,但为什么low也要这么做呢?
因为low的定义如上,也就是说如果没有子孙与u的祖先相连的话,dfn[u]一定是它和它的所有子孙中dfn最小的(因为它的所有子孙一定比他后搜到)。将u存入stack[ ]中,并将vis[u]设为true
stack[ ]有什么用?
如果u在stack中,u之后的所有点在u被回溯到时u和栈中所有在它之后的点都构成强连通分量。(也就是上文中所说的开个栈记录)遍历u的每一个能到的点,如果这个点dfn[ ]为0,即仍未访问过,那么就对点v进行dfs,然后low[u]=min{low[u],low[v]}
low[ ]有什么用? 应该能看出来吧,就是记录一个点它最大能连通到哪个祖先节点(当然包括自己)
如果从u遍历这个点之前这个点就被遍历到了,那么看它当前有没有在stack[ ]里,如果有(要么这个点是u的祖先,要么这个点与u的某个祖先强连通,反正这个点能到达u),说明这个点肯定能到达u,同样u能到达他,他俩强联通,那么low[u]=min{low[u],low[v]}
如果已经被弹掉了,说明无论如何这个点也不能与u构成强连通分量,因为它不能到达u(当处理强连通分量时才将元素弹出栈。处理包含这个点的强连通分量时没有处理掉u,就说明u不在它的强连通分量里)假设我们已经dfs完了u的所有的子树,那么之后无论我们再怎么dfs,u点的low值已经不会再变了。
那么如果dfn[u]=low[u]这说明了什么呢?
再结合一下dfn和low的定义来看看吧
dfn表示u点被dfs到的时间,low表示u和u所有的子树所能到达的u的祖先中dfn最小的。
这说明了u点及u点之下的所有子节点没有边是指向u的祖先的了,即我们之前说的u点与它的还在栈中的子孙节点构成了一个最大的强连通图即强连通分量
此时我们得到了一个强连通分量,把所有的u点以后压入栈中的点和u点一并弹出,将它们的vis[ ]置为false,如有需要也可以给它们染上相同颜色(后面会用到,用于缩点等等)
代码大概长成这样
      

对了,tarjan一遍不能搜完所有的点,因为存在孤立点或者其他
所以我们要对一趟跑下来还没有被访问到的点继续跑tarjan
怎么知道这个点有没有被访问呢?
看看它的dfn是否为0!
      
非常简短的tarjan复杂度证明:
思考每个点最多被dfs一次,所以均摊下来复杂度是O(n)的
证毕
五、扩展:
tarjan缩点:
1.什么时候要用缩点
众所周知,有向无环图总是有着一些蜜汁优越性,因为没有环,你可以放心的在上面跑dfs,搞DP,但如果是一张有向有环图,事情就会变得尴尬起来了
思考一下会发现如果不打vis标记就会t飞(一直在环里绕啊绕),但是如果打了,又不一定能保证最优解
而你一看题目却发现显然根据一些贪心的原则,这个环上每个点的最大贡献都是整个环的总贡献
这个时候缩点就显得很有必要了,因为单个点的贡献和整个环相同,为什么不去把整个环缩成一个超级点呢?
这个环只是为了好理解,事实上他应该是一个强连通分量,显然如果只缩掉一个强连通图,图中仍然有环存在
缩点的一个栗子
    
 -----------> 
2.怎么缩点
还记得之前tarjan里的染色吗?
我们只需要把同一颜色的点权加到一块,然后把该颜色指向不同颜色的边建好就可以了
代码就不贴了,因为不同的题有不同的处理方法
无向图tarjan求环:
每次tarjan递归时记录父亲节点到儿子节点走的边的对应相反边(因为无向图对于一条边用前向星存的话要插入2次),若儿子在不走这条边的情况下仍能得到小于dfn的low,即可走另一条路径到达父亲节点的祖先,说明有一个环。并且若干个相交的环会以一个强连通分量的形式呈现出来。
无向图tarjan求割点:www.cnblogs.com/collectionne/p/6847240.html
该博客有一处low的维护操作与普通tarjan不同:low[u] = min(low[u], dfn[v]);
这里解释一下:若v已经被遍历过了,这时遍历到u发现u与v有连边。这说明什么?v还没有被回溯。因为这时无向图,既然u能到v,那v也能到u,当回溯到v时,v所能到的点必然都已经被遍历完了。这里刚遍历到u,不就说明v还没有被回溯到嘛。这样,v不就是u的祖先了嘛。
大量摘自洛谷博客:初探tarjan算法(求强连通分量),略有修改。在此对作者:Styx 表示真挚的感谢。
Tarjan算法初步的更多相关文章
- 【原创】tarjan算法初步(强连通子图缩点)
		
[原创]tarjan算法初步(强连通子图缩点) tarjan算法的思路不是一般的绕!!(不过既然是求强连通子图这样的回路也就可以稍微原谅了..) 但是研究tarjan之前总得知道强连通分量是什么吧.. ...
 - 强连通分量与tarjan算法初步运用
		
模板题:B3609 [图论与代数结构 701] 强连通分量 题目描述 给定一张 n 个点 m 条边的有向图,求出其所有的强连通分量. 注意,本题可能存在重边和自环. 输入格式 第一行两个正整数 n , ...
 - 图论初步-Tarjan算法及其应用
		
暑假刷了一堆Tarjan题到头来还是忘得差不多. 这篇博客权当复习吧. 一些定义 无向图 割顶与桥 (划重点) 图G是连通图,删除一个点表示删除此点以及所有与其相连的边. 若删除某点u后G不再连通,那 ...
 - 有向图强连通分量的Tarjan算法
		
有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...
 - 点/边 双连通分量---Tarjan算法
		
运用Tarjan算法,求解图的点/边双连通分量. 1.点双连通分量[块] 割点可以存在多个块中,每个块包含当前节点u,分量以边的形式输出比较有意义. typedef struct{ //栈结点结构 保 ...
 - 割点和桥---Tarjan算法
		
使用Tarjan算法求解图的割点和桥. 1.割点 主要的算法结构就是DFS,一个点是割点,当且仅当以下两种情况: (1)该节点是根节点,且有两棵以上的子树; (2)该节 ...
 - Tarjan算法---强联通分量
		
1.基础知识 在有向图G,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子 ...
 - (转载)LCA问题的Tarjan算法
		
转载自:Click Here LCA问题(Lowest Common Ancestors,最近公共祖先问题),是指给定一棵有根树T,给出若干个查询LCA(u, v)(通常查询数量较大),每次求树T中两 ...
 - 强连通分量的Tarjan算法
		
资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...
 
随机推荐
- [转帖]影驰首发PCIe 4.0 SSD:群联AMD合作主控飚出5GB/s
			
影驰首发PCIe 4.0 SSD:群联AMD合作主控飚出5GB/s https://www.cnbeta.com/articles/tech/851275.htm 硬件发展的真快.. AMD刚刚发布的 ...
 - SPOJ 703 SERVICE - Mobile Service 题解
			
题面 好题啊!~ 设f[i][j][k][l]表示已经处理完前i个请求后,a在j,b在k,c在l的最小值是多少: 那么f[i][p[i]][k][l]=min(f[i][p[i]][k][l],f[i ...
 - Android引用多媒体
			
res目录下,创建raw目录(Android会自动识别这个目录),如果自己创建的目录,可能无效底下的mp3格式,mp4格式的文件名必须小写. 引用方式: mediaPlayer = MediaPlay ...
 - 带EFI支持的GRUB2安装全记录
			
版权归作者所有,任何形式转载请联系作者. 作者:keenshoes(来自豆瓣) 来源:https://www.douban.com/note/210077866/ 关键词:EFIGRUB2efibo ...
 - ELK的搭建以及使用
			
一.架构如图: 二.工作机制: 在需要收集日志的应用上安装filebeat(需要修改配置文件,配置文件稍后介绍),启动filebeat后,会收集该应用的日志推送给redis,然后logstash从re ...
 - 20.AutoMapper 之理解你的映射(Understanding Your Mappings)
			
https://www.jianshu.com/p/4f5c14fbf1c2 理解你的映射(Understanding Your Mappings) AutoMapper 为你的映射创建执行计划.在调 ...
 - 不用再去找rem了,你想要的rem都在这
			
一.兼容性. 目前,IE9+,Firefox.Chrome.Safari.Opera 的主流版本都支持了rem(大胆用吧,目前几乎所有手机浏览器都支持rem) 二.什么是rem. rem是相对于根元素 ...
 - 为什么现在UML很少用了
			
新霸哥发现UML在面向对象的设计中的需求,相关行为.一些体系结构的实现提供了一套综合完整的表示法,但是由于使用的人比较少,初学者不容易快速入门,所以就导致了UML不是那么的受欢迎. UML在开发中有什 ...
 - DataWorks(数据工场)
			
一.DataWorks(数据工场) DataWorks系列视频 https://help.aliyun.com/video_list/107549.html?spm=a2c4g.11174359.3. ...
 - icmp, IPPROTO_ICMP - Linux IPv4 ICMP 核心模块.
			
DESCRIPTION 描述 本网络核心协议模块实现了基于 RFC792 协议中定义的<互联网控制报文协议>.它针对网络主机间通讯出错的情况作出回应并给出诊断信息.用户不能直接使用本模块. ...