昨天在打牛客多校的时候遇到了一道与连通性有关的图论题,笔者一眼就看出这题考察的知识点是Tarjan算法,但是笔者上次写Tarjan算法还是三年前的事情(太惭愧了qaq),于是笔者和队友在赛时花了一个小时时间学习了Tarjan算法成功通过了此题,故写下这篇博客进一步加深印象,同时也是分享自己对于该算法的理解
什么是Tarjan算法?
Tarjan是一位伟大的美国计算机科学家的名字,他发明了许多好用的算法和数据结构,以他的名字命名,这里我们主要介绍的是与连通性有关的Tarjan算法
有向图强连通分量的Tarjan算法
什么是强连通分量?
首先我们要知道强连通的概念:有向图 G 强连通是指,G 中任意两个结点连通,换句话说就是 G 中任意两个结点可以相互到达,强连通分量指的是从这张有向图中选出一个最大的子图,使得这张子图是强连通的
怎么求强连通分量?
在介绍Tarjan算法求强连通分量前,首先我们要知道一个很重要的概念叫DFS生成树,如图所示:
这颗树是在我们进行DFS的过程中,按照搜索的顺序遍历过程中生成的一颗树,我们会发现这颗树上有4种不同颜色的边:
1.树边(黑色边):每次搜索到一个还未被访问的结点形成的边
2.返祖边(红色边):指向祖先结点的边
3.横叉边(蓝色边):搜索的过程中遇到一个已经访问过的结点形成的边,但该点不是当前结点的祖先
4.前向边(绿色边):搜索过程中遇到子树中的结点形成的边
为什么我们要在这里介绍DFS生成树呢?
我们观察树的结构发现,对于属于某一个强连通分量的结点u,如果在搜索树中它是所在强连通分量第一个被遍历到的点,那么该强连通分量中的剩余点一定在以u为根的子树中,这个性质对我们求出强连通分量具有重要的作用
学习完搜索树后,我们终于可以开始介绍Tarjan算法求有向图强连通分量了
Tarjan算法是基于对图进行深度优先搜索,我们视每个连通分量为搜索树中的一棵子树,在搜索过程中,维护一个栈,每次把搜索树中尚未处理的节点加入栈中
在算法的过程中我们需要维护几个变量:
dfn[u]: u 的dfs是序,即在DFS的过程中结点 u 被搜索到的次序
low[u]:在 u 的子树中能够回溯到的最早的已经在栈内的点
我们观察树的结构,很自然能够发现,对于一个强连通分量内的点,它的 low 值要么等于该强连通分量的根结点的 dfn 值,要么是该强连通分量通过一条边
能够到达的结点的 dfn 值
进一步的,我们可以发现对于一颗子树,子树中其它结点的 dfn 值一定会大于根结点的 dfn 值;同时,子树中结点的 low 值一定不小于根结点的 dfn 值
那么维护这两个变量有什么用呢?
我们注意到刚才上面加粗的那句话,很自然能够想到:对于一个强连通分量,有且只有根结点的 dfn 值会等于 low 值,所以我们考虑把当前搜索到的元素加入到一个栈中,不断弹出栈中元素,直到找到 dfn 值和 low 值相等的结点,那么这些点就是以这个 dfn 值和 low 值 相等的点为根的一个强连通分量
所以现在我们的瓶颈就在于如何维护 dfn 和 low 的信息
在搜索的过程中,我们考虑当前的结点 u 以及与它相连的结点 v ,一共有三种情况:
-
v 未被访问过:继续对 v 进行dfs,在回溯过程中用 low[v] 更新 low[u] ,因为 u 和 v 之间存在连边,所以 v 能够回溯到的点, u 一定能回溯到
-
v 被访问过且在栈中,那么 \(low[u] = min(low[u],dfn[v])\)
-
v 被访问过且不在栈中,那么说明 v 所在的强连通分量已经被处理,不需要进行操作
综上所述,我们就能够在 \(O(n+m)\) 的时间复杂度内求出强连通分量了
代码如下:
int dfn[N],low[N],dfncnt,s[N],in_stack[N],tp;
int scc[N],sc;
int sz[N];
vector<int> g[N];
void tarjan(int u){
low[u]=dfn[u]=++dfncnt,s[++tp]=u,in_stack[u]=1;
for(auto v:g[u]){
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else {
if(in_stack[v])
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
++sc;
while(s[tp]!=u){
scc[s[tp]]=sc;
sz[sc]++;
in_stack[s[tp]]=0;
--tp;
}
scc[s[tp]]=sc;
sz[sc]++;
in_stack[s[tp]]=0;
tp--;
}
}
标签:结点,连通性,连通,Tarjan,算法,dfn,low,分量
From: https://www.cnblogs.com/isletfall/p/18338743