算法详解之Tarjan
“tarjan陪伴强联通分量
生成树完成后思路才闪光
欧拉跑过的七桥古塘
让你 心驰神往”----《膜你抄》
一、tarjan求强连通分量
- 什么是强连通分量?
引用来自度娘的一句话:
“有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。
如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。”
一脸懵逼......不过倒也不难理解。
反正就是在图中找到一个最大的图,使这个图中每个两点都能够互相到达。这个最大的图称为强连通分量,同时一个点也属于强连通分量。

如图中强连通分量有三个:1-2-3,4,5
- 强连通分量怎么找?
噫......当然,通过肉眼可以很直观地看出1-2-3是一组强连通分量,但很遗憾,机器并没有眼睛,所以该怎么判断强连通分量呢?
如果仍是上面那张图,我们对它进行dfs遍历。

可以注意到红边非常特别,因为如果按照遍历时间来分类的话,其他边都指向在自己之后被遍历到的点,而红边指向的则是比自己先被遍历到的点。
如果存在这么一条边,那么我们可以yy一下,emmmm.......
从一个点出发,一直向下遍历,然后忽得找到一个点,那个点竟然有条指回这一个点的边!
那么想必这个点能够从自身出发再回到自身
想必这个点和其他向下遍历的该路径上的所有点构成了一个环,
想必这个环上的所有点都是强联通的。
但只是强联通啊,我们需要求的可是强连通分量啊......
那怎么办呢?
我们还是yy出那棵dfs树
不妨想一下,什么时候一个点和他的所有子孙节点中的一部分构成强连通分量?
他的子孙再也没有指向他的祖先的边,却有指向他自己的边
因为只要他的子孙节点有指向祖先的边,显然可以构成一个更大的强联通图。

比如说图中红色为强连通分量,而蓝色只是强联通图
那么我们只需要知道这个点u下面的所有子节点有没有连着这个点的祖先就行了。
但似乎还有一个问题啊......
我们怎么知道这个点u它下面的所有子节点一定是都与他强联通的呢?
这似乎是不对的,这个点u之下的所有点不一定都强联通

那么怎么在退回到这个点的时候,知道所有和这个点u构成强连通分量的点呢?
开个栈记录就行了
什么?!这么简单?
没错就是这么简单
如果在这个点之后被遍历到的点已经能与其下面的一部分点(也可能就只有他一个点)已经构成强连通分量,即它已经是最大的。
那么把它们一起从栈里弹出来就行了。
所以最后处理到点u时如果u的子孙没有指向其祖先的边,那么它之后的点肯定都已经处理好了,一个常见的思想,可以理解一下。
所以就可以保证栈里留下来u后的点都是能与它构成强连通分量的。
似乎做法已经明了了,用程序应该怎么实现呢?
所以为了实现上面的操作,我们需要一些辅助数组
(1)、dfn[ ],表示这个点在dfs时是第几个被搜到的。
(2)、low[ ],表示这个点以及其子孙节点连的所有点中dfn最小的值
(3)、stack[ ],表示当前所有可能能构成是强连通分量的点。
(4)、vis[ ],表示一个点是否在stack[ ]数组中。
那么按照之上的思路,我们来考虑这几个数组的用处以及tarjan的过程。
假设现在开始遍历点u:
(1)、首先初始化dfn[u]=low[u]=第几个被dfs到
dfn可以理解,但为什么low也要这么做呢?
因为low的定义如上,也就是说如果没有子孙与u的祖先相连的话,dfn[u]一定是它和它的所有子孙中dfn最小的(因为它的所有子孙一定比他后搜到)。
(2)、将u存入stack[ ]中,并将vis[u]设为true
stack[ ]有什么用?
如果u在stack中,u之后的所有点在u被回溯到时u和栈中所有在它之后的点都构成强连通分量。
(3)、遍历u的每一个能到的点,如果这个点dfn[ ]为0,即仍未访问过,那么就对点v进行dfs,然后low[u]=min{low[u],low[v]}
low[ ]有什么用?
应该能看出来吧,就是记录一个点它最大能连通到哪个祖先节点(当然包括自己)
如果遍历到的这个点已经被遍历到了,那么看它当前有没有在stack[ ]里,如果有那么low[u]=min{low[u],low[v]}
如果已经被弹掉了,说明无论如何这个点也不能与u构成强连通分量,因为它不能到达u
如果还在栈里,说明这个点肯定能到达u,同样u能到达他,他俩强联通。
(4)、假设我们已经dfs完了u的所有的子树那么之后无论我们再怎么dfs,u点的low值已经不会再变了。
那么如果dfn[u]=low[u]这说明了什么呢?
再结合一下dfn和low的定义来看看吧
dfn表示u点被dfs到的时间,low表示u和u所有的子树所能到达的点中dfn最小的。
这说明了u点及u点之下的所有子节点没有边是指向u的祖先的了,即我们之前说的u点与它的子孙节点构成了一个最大的强连通图即强连通分量
此时我们得到了一个强连通分量,把所有的u点以后压入栈中的点和u点一并弹出,将它们的vis置为false,如有需要也可以给它们打上相同标记(同一个数字)

对了,tarjan一遍不能搜完所有的点,因为存在孤立点或者其他
所以我们要对一趟跑下来还没有被访问到的点继续跑tarjan
怎么知道这个点有没有被访问呢?
看看它的dfn是否为0!

这看起来似乎是o(\(n^2\))的复杂度,但其实均摊下来每个点只会被遍历一遍
所以tarjan的复杂度为o(\(n\))。
tarjan到此结束
参考博文:https://www.cnblogs.com/stxy-ferryman/p/7779347.html
算法详解之Tarjan的更多相关文章
- Tarjan算法详解
Tarjan算法详解 今天偶然发现了这个算法,看了好久,终于明白了一些表层的知识....在这里和大家分享一下... Tarjan算法是一个求解极大强联通子图的算法,相信这些东西大家都在网络上百度过了, ...
- BM算法 Boyer-Moore高质量实现代码详解与算法详解
Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- [转] KMP算法详解
转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的K ...
- 【转】AC算法详解
原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...
- KMP算法详解(转自中学生OI写的。。ORZ!)
KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...
- EM算法详解
EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...
- 安全体系(二)——RSA算法详解
本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...
随机推荐
- sqlserver中产生随机字符,随机数
SELECT REPLACE(NEWID(),'-','') select replicate(char(cast(rand()*1000 as int)%26+97) +char(cast(rand ...
- springBoot怎样访问静态资源?+静态资源简介
1.静态资源 怎样通过浏览器访问静态资源? 注意:不需要加static目录.因为只是告诉springboot目录,而不是静态资源路劲. 这时访问路径就需要加上/static
- ueditor百度编辑器destoon的word图片转存功能
图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM ...
- history API,判断页面是否是在跳转链接后返回
https://www.cnblogs.com/accordion/p/5699372.html history.replaceState(history.state, null, "htt ...
- [Luogu] 网络
https://www.luogu.org/problemnew/show/P3250 树链剖分 + 线段树 + 优先队列 要求未被影响的请求中最大的 所以每次将每条路径在整棵树上的补集的每个节点的优 ...
- 【概率论】1-4:事件的的并集(Union of Events and Statical Swindles)
title: [概率论]1-4:事件的的并集(Union of Events and Statical Swindles) categories: Mathematic Probability key ...
- open, create, close
1.open 系统调用 说明: 调用open函数打开或者创建一个文件.函数定义如下: #include <fcntl.h> int open(const char *pathname, ...
- sublime 3 text 中运行Java
1.首先确保JDK安装和配置完成 2.在JDK的bin目录下添加runJava.bat文件 @echo offcd %~dp1echo Compiling %~nx1...if exist %~n1. ...
- 7月清北学堂培训 Day 5
今天是钟皓曦老师的讲授~ 动态规划 动态规划的三种实现方法: 1.递推: 2.递归: 3.记忆化: 举个例子: 斐波那契数列:0,1,1,2,3,5,8…… Fn = Fn-1 + Fn-2 1.我们 ...
- HDU 1074 Doing Homework ——(状态压缩DP)
考虑到n只有15,那么状压DP即可. 题目要求说输出字典序最小的答案的顺序,又考虑到题目给出的字符串本身字典序是递增的,那么枚举i的时候倒着来即可.因为在同样完成的情况下,后选字典序大的,小的字典序就 ...