有向图强连通分量的Tarjan算法及模板
【有向图强连通分量】
在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强联通(strongly connected),如果有向图G的每两个顶点都强联通,称有向图G是一个强联通图。非强联通图有向图的极大强联通子图(对于“极大”的理解,就是在一个局部子图中不能再大。就像是数学中的求一个函数中的极大值和极小值一样,例如求函数f(x)的极大值和极小值,变量x可以有不同的区间,所以在x的不同区间内就会有不同的极大值或极小值。) 称为强联通分量。直接根据定义用双向遍历取交集求强联通分量,时间复杂度为O(N……2+M)。更好的方法是kosaraju和tarjan算法,两者的时间复杂度都是O(N+M)。先介绍tarjan算法。
(点对(u,v)称为边或弧,若边的点对(u,v)有序则称为有向边,其中u称为tou,v称为尾)
(摘自wiki:https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
【定义】:
tarjan算法是基于对图深度优先搜索的算法,每个强联通分量为搜索树的一颗子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中节点是否为一个强联通分量。
定义dfn(u)为节点u搜索的次序编号(时间戳),low(u)为u或者u的子树能够追溯到的最早的栈中节点的次序号。//Low[u]是点集{u点及以u点为根的子树}中(所有反向弧)能指向的(离根最近的祖先v)的 DFN[v]值(即v点时间戳) //Low[u]表示以u点为父节点的子树能连接到 [栈中] 最上端的点 的DFN值(换句话说是最小的DFN,因为最上端的DFN是最小的嘛)
由定义可以得:
low(u)=min( dfn(u), low(v), dfn(v));
当dfn(u)=low(u)时,以u为根的搜索子树上的所有节点是一个强连通分量。
【应用】:
Tarjan是一个对图的分析的强有力的算法,主要应用有:有向图的强连通分量、无向图的割点桥与双连通分量、LCA(最近公共祖先)
【黑匣子】
先最初调用
1、init()
2、把图用add 存下来,注意图点标为1-n,若是[0,n-1]则给所有点++;
3、调用tarjan_init(n); 再调用suodian();
4、新图就是vector<int>G[]; 新图点标从1-tar ;
5、对于原图中的每个点u,都属于新图中的一个新点Belong[u];
新图一定是森林。
6、新图中的点u 所表示的环对应原图中的vector<int> bcc[u];
7、旧图中u在新图中所属的点是Belong[u];
Tarjan的实现主体就是dfs。可以自己画一个图感受一下,有向图中,每个强联通分量都是由多个环组成的,且这些环包含了集合中的所有元素且这些环两两相交,那么如果我们对于其中的任意一个元素进行dfs的话,最终这个强连通分量里的元素就会形成一颗子树,并且如果我们把我们的起始元素看作一棵树的根节点的话,那么它的子树中(也就是这个强联通分量中)一定会有节点它的父节点方向连边,并且这些向回连的边最终都会通到根节点,并且叶节点必然会向回连边(这是很显然的)。这样才能满足这个子树中的每个节点都能到达其他的各个节点。
知道了这些性质后,我们就可以进行操作了:
我们将每个强联通分量视为一个集合,一开始所有节点都是各自独立的集合,开两个数组dfn[ ]和low[ ],dfn记录的是节点被访问的顺序,low[i]记录i节点所在集合的代表元素的dfn值(这里类似于并查集),显然对于一个新的节点,集合的代表元素就是它本身,dfn[i]=low[i],。然后我们对其进行dfs,首先将它加入一个栈内,然后对它的每一个可以到达的节点进行dfs,如果它连接的节点是它的一个父节点(或祖父节点,也就是刚刚dfs路径上的点),那么low[i] = min( low[i], low[to] );如果它连接的节点已经被访问过(也就是已经dfs过)并且不是该节点的父节点或祖父节点,直接跳过(因为既然那个节点已经dfs过,而当前节点又是本次才访问到,那么说明那个节点出发一定不能到达当前节点,也就是说它们一定不在一个强联通分量里);我们看看上面这部分操作,它和并查集的操作是很像的,我们相当于将dfs路径上的环合并成了一个集合(相交环也被合成了一个集合),并且代表元素是最先访问的那个点,而由定义可知所有相交环都是一个强联通图,那么我们在回溯时,判断该节点的low[ ]是否等于dfn[ ],如果不相等,那么不做处理,直接返回,如果相等的话就说明该节点是一个集合的代表元素,我们在将刚才栈中的所有在该节点后面入栈的还在栈内的元素(包括它本身)出栈,这些元素就是一个强联通分量。这样的正确性是显然的,我们相当于将所有已经构建的集合保存了下来,而这些集合都是由相交环构成的,而相交环构成的集合一定是一个强联通分量,,所以我们构造出来的集合就一定是原图的强联通分量!
【算法伪代码如下】
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) //如果节点还在栈内
low[u]=min(low[u],dfn[v])
if(dfn[u]==low[u]) //如果节点u是强联通分量的根
repeat
v=s.pop //将v退栈,为该强连通分量中的一个顶点
print v
until (u==v)
}
算法:
void tarjan(int i)
{
int j;
dfn[i]=low[i]=++index //将节点u设定次序编号和low初值
instack[i]=true; //将节点u压入栈中
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])
{
cnt++;
do
{
j=stap[stop--];
instack[j]=false;
belong[j]=cnt;
}while(j!=i);
}
} void solve()
{
int i;
stop=cnt=index=;
memset(dfn,,sizeof(dfn));
for(i=; i<=n; i++)
{
if(!dfn[i])
tarjan(i);
}
}
有向图强连通分量的Tarjan算法及模板的更多相关文章
- 有向图强连通分量的Tarjan算法
有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...
- 算法笔记_144:有向图强连通分量的Tarjan算法(Java)
目录 1 问题描述 2 解决方案 1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连 ...
- 【转】有向图强连通分量的Tarjan算法
原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...
- 【转载】有向图强连通分量的Tarjan算法
转载地址:https://www.byvoid.com/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly conn ...
- 有向图强连通分量的Tarjan算法(转)
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 『图论』有向图强连通分量的Tarjan算法
在图论中,一个有向图被成为是强连通的(strongly connected)当且仅当每一对不相同结点u和v间既存在从u到v的路径也存在从v到u的路径.有向图的极大强连通子图(这里指点数极大)被称为强连 ...
- Java实现有向图强连通分量的Tarjan算法
1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为 ...
- 强连通分量的Tarjan算法
资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...
- 有向图强连通分量的Tarjan算法和Kosaraju算法
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
随机推荐
- 【bzoj3514】Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树
题目描述 N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 输入 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密.接下来M行,代表图中的每条边 ...
- GDI绘图中的映射模式CDC::SetMapMode()
原文链接:http://blog.csdn.net/charlessimonyi/article/details/8264572 在GDI绘图前,一般要设置映射模式.映射模式是什么呢?它是逻辑长度单位 ...
- 【CF Round 434 B. Which floor?】
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- 【NOIP模拟赛】Evensgn 的债务 乱搞
biubiu~~~ 我们发现按照这道题的题意我们把一个个人的前后(欠钱,被欠钱)都缩一下,那么他对其他人没有影响,那么我们就可以依次缩完每个人,而且每个人最后的状态都是要买欠要么被欠,那么我们可以知道 ...
- c++ STL(2)
Vector: #include "stdafx.h" #include<iostream> #include<vector> #include<al ...
- 慕课网javascript 进阶篇 第九章 编程练习
把平常撸的码来博客上再撸一遍既可以加深理解,又可以理清思维.还是很纯很纯的小白,各位看官老爷们,不要嫌弃.最近都是晚睡,昨晚也不例外,两点多睡的.故,八点起来的人不是很舒服,脑袋有点晕呼呼,鉴于昨晚看 ...
- BigDecimal与Long、int之间的互换
在实际开发过程中BigDecimal是一个经常用到的数据类型,它和int Long之间可以相互转换. 转换关系如下代码展示: int 转换成 BigDecimal 数据类型 //int 转换成 big ...
- uoj198【CTSC2016】时空旅行
传送门:http://uoj.ac/problem/198 [题解] 首先y.z是没有用的.. 然后式子就是w = (x0-xi)^2+ci的最小值,化出来可以变成一个直线的形式. 然后我们可以用线段 ...
- 【mysql】索引与排序、重复索引、冗余索引
索引与排序 排序可能发生2种情况: 1: 对于覆盖索引,直接在索引上查询时,就是有顺序的, using index 2: 先取出数据,形成临时表做filesort(文件排序,但文件可能在磁盘上,也可能 ...
- CSS3 渐变(Gradients)
参考: http://www.runoob.com/css3/css3-gradients.html CSS3 渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳的过渡. 以前,你必 ...