Tarjan的强连通分量算法
Tarjan算法用于寻找图G(V,E)中的所有强连通分量,其时间复杂度为O(|V|+|E|)。
所谓强连通分量就是V的某个极大子集,其中任意两个结点u,v在图中都存在一条从u到v的路径。
Tarjan的算法的流程是通过深度优先搜索遍历每个顶点,并且维护以下属性dfn,low,instk,p其中dfn表示该顶点第一次被访问时的次序,instk需要与一个栈stk配合使用,stk用于记录从某个顶点出发,尚未被包含进强连通分量的所有顶点,而instk用于记录一个顶点是否还存在于stk中,low表示从该结点出发可以访问到的所有在栈中的顶点中dfn属性最小的顶点的dfn值,p表示顶点所处强连通分量的代表顶点。
算法的流程如下:
tarjan(u, stk)
if(u.dfn != 0)
return
u.dfn = order()
u.low = u.dfn
u.instk = true
stk.push(u)
for (u, v) in E
targin(v)
if(v.instk)
u.low = min(u.low, v.low)
if(u.dfn == u.low)
while(true)
top = stk.pop()
top.instk = false
top.p = u
if(top == u)
break
其中order()表示分配下一个次序号,要求order()方法的返回值随调用次数增加而递增,且不能少于1,可以通过维护一个计数器实现。我们需要对每个V中的顶点调用上述Tarjan流程即可保证强连通分量的正确分离。
说明时间复杂度,由于每个结点被访问都会设置dfn值,因此一个结点最多只会被访问一次,其4~7行总执行次数不可能超过|V|。而8~11行中每次都会使用一条完全不同的边,其总执行次数不可能超过|E|。12~18行每次循环都会令一个顶点弹出stk,由于只有4~7行会向栈中压入一个顶点,因此总执行次数不会超过|V|。因此总的时间复杂度为O(|V|+|E|)。
再说明算法正确性。从两个角度说明:1.任意两个连通顶点u,v都会拥有相同的p属性值,即u.p=v.p。2.任意两个不连通顶点都会拥有不同的p属性值。
命题1:对于栈中的元素x,y,若x.dfn<y.dfn,则x必定在y之后出栈。因为dfn属性与入栈的顺序是一致的。
命题2:若顶点x被加入栈中,则栈中所有现存顶点到x都有一条路径。假设当栈中所有顶点满足命题时,我们通过栈中的某个顶点y,将其后置顶点x加入到栈中,由于假设可知栈中y及y之下所有的顶点都能访问到x。对于y之上的第一个顶点z,若z不为x,则由于z在回溯到y时,没有从栈中弹出,故z.dfn>z.low,即z能访问到z之下的某个顶点,故z能访问到x。因此由归纳法可知命题成立。
命题3:当我们确定了栈中某个顶点u的low值时,在栈中u之上所有的顶点和u必定处在同一个强连通分量中。假设当栈中所有顶点满足这一性质时,我们压入顶点u,并利用深度优先搜索算法遍历u的后置顶点。当我们确定了u的low值时,若在栈中u之上还存在顶点v,不妨设v为u之上的第一个顶点,显然v.dfn>u.dfn,即v的回溯应该发生在u回溯之前,而v没有被出栈,意味着v.low<v.dfn,即v能访问到栈中某个v之下的顶点z,v和u是连通的。依旧是使用了归纳法。
对于1,不妨设u.dfn<v.dfn,由于v能访问到u,故v.low<=u.dfn,而由命题2知道,所有栈中v之下的顶点x都满足x.low<=v.low<=u.dfn,即v出栈时必定会导致u的出栈,故v.p=u.p。
对于2,当u和v被设置相同的p值时,意味着二者同时出栈。而由命题3可知u和v必定是连通的。
因此当我们对V中每个顶点调用Tarjan流程时,将会保证强连通分量的正确分离。
Tarjan的强连通分量算法的更多相关文章
- 【学习整理】Tarjan:强连通分量+割点+割边
Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量. 算法可以在 ...
- Tarjan求强连通分量,缩点,割点
Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...
- CCF 高速公路 tarjan求强连通分量
问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的 ...
- Tarjan求强连通分量、求桥和割点模板
Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...
- UESTC 901 方老师抢银行 --Tarjan求强连通分量
思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...
- tarjan求强连通分量+缩点+割点以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题
Summer Holiday Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】
Road Networks Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit Stat ...
随机推荐
- 使用 nvm 管理多版本 node
首先,使用下面的命令来安装 nvm $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | b ...
- 如何用 Java 实现 Web 应用中的定时任务
定时任务,是指定一个未来的时间范围执行一定任务的功能.在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有其自己的语法及解决方案,windows操作系统把它叫做任务计 ...
- ResNet网络结构
MSRA(微软亚洲研究院)何凯明团队的深度残差网络(Deep Residual Network)在2015年的ImageNet上取得冠军,该网络简称为ResNet(由算法Residual命名),层数达 ...
- 在Blender上安装RenderMan插件
2018/3/27 Download and Install Blender itself Download RenderMan Installer (Need to register an acco ...
- 【MFC】SetWindowPos函数使用详解
摘自: http://wenku.baidu.com/link?url=hYKs20rYA13TTdMl9gJ378GNOsxH1DPZPkYZVEIcipATlVBMLzjWdpd2-29fm-tq ...
- 利用git bash和git gui向git远程仓库提交文件
1.首先在该文件夹下git init 2.然后在github下面创建一个新仓库去存储你的代码 3.然后利用add添加远程仓库 4.然后点击stage changed 5.最后点击长传 参考链接:htt ...
- webpack新版本4.12应用九(配置文件之入口和上下文(entry and context))
entry 对象是用于 webpack 查找启动并构建 bundle.其上下文是入口文件所处的目录的绝对路径的字符串. context string 基础目录,绝对路径,用于从配置中解析入口起点(en ...
- INSTALL_FAILED_SHARED_USER_INCOMPATIBLE的问题
eclipse编译出来的apk,安装时报出INSTALL_FAILED_SHARED_USER_INCOMPATIBLE的错误. 原因:apk的AndroidManifest.xml中声明了andro ...
- (转)【Android】获取Mac地址【2】
[Android]获取Mac地址[2] 之前写了[Android]获取Mac地址[1]有些不够详细,现在贴上一些其他代码,仅供参考. (1) 调用android 的API: NetworkInterf ...
- jquery中ajax异步调用接口
之前写过一个原始的.无封装的页面,没有引入任何外部js,直接实例化Ajax的XmlRequest对象去异步调用接口,参见Ajax异步调用http接口后刷新页面,可对比一下. 现在我们用jquery包装 ...