Tarjan算法之求强连通分量
最近又学习了强连通分量的Tarjan求法,先是看了别人的许多博客,才勉勉强强看懂,自己写完博客后感到十分显然,也没有表面上看的那么高大上。
好了,转入正题,先说说什么是强连通分量:
有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。----摘自百度百科。
简单来说,就是一个有向图中,有一个子图,子图中的任意两个点都能互相到达,则这个子图就是整个图的强联通分量,这么来说,显然的是,整张图一定是被分割成了几个强连通分量,我们举个例子看一下:
显而易见的1,2,3号节点是可以互相到达的,所以1,2,3组成的子图是强联通分量,此外,5和4号节点单独成为一个强连通分量,于是,这张图就有了三个强连通分量至于怎么微妙地求出这几个强连通分量,这里用的是Tarjan算法,看完之后就会恍然大悟的。
首先,我们定义一个数组,dfn[],这个数组存的是当前节点的时间戳(什么是时间戳?时间戳就是当前节点的DFS序,也可以理解为第一次遍历到当前节点的时间),还有low[]数组,这个数组存的是当前节点能够追溯到的时间戳最小的节点的时间戳,也就相当于这个节点所在的强连通分量的“根节点”。可能有点难理解,多读几遍,说不定能理解一点。
那么low【】数组和dfn【】数组要如何维护呢?
dfn【】数组,显然,在遍历到该节点时记录,以后就不用动了,而low【】数组,是在扩展点时更新的,比如说,当前节点为u,将要扩展的点为v,若dfn[v]==low[v]&&vis[v]==false,也就是说,v点是可以到达u点的(因为u点没有被访问结束,说明u点是由v点扩展出来的),这样就出现了一个环。!!!注意!!!有环就有强连通分量,想想是不是?环上的所有的点组成了一个强连通分量,之后只要vis[u]=false,low[u]=low[v],渐渐地回溯并找其他的点即可
我们还是以上图为例:
假设从1点开始遍历,dfn[1]=1,low[1]=1,继续2点,dfn[2]=2,low[2],继续3点,dfn[3]=3,low[3]=3,继续深搜,发现下一个点是1,有趣,满足条件dfn[v]==low[v]&&vis[v]==false,修改low【3】=1,且没有要拓展的点,回溯。边回溯边修改,low【2】=1,继续回溯,到一,访问结束。接着找其他点,继续访问。最后访问的结果应该是这样的:
i :1,2,3,4,5。
dfn【】:1,2,3,4,5。
low【】:1,1,1,4,5.
所以一共有三个强连通分量,分别是以1,4,5为根的。代码贴上(大佬勿喷):
#include <bits/stdc++.h>
using namespace std;
int dfn[10010],low[10010];
bool vis[10010];
vector<int> son[10010];
int n,m;
int tim=0;
int ans=0;
template <typename T> void read(T &x) {
x = 0; char c = getchar ();
for (; !isdigit(c); c = getchar ());
for (; isdigit(c); c = getchar ()) x = x * 10 + c - '0';
}
void Tarjan(int x){
vis[x]=true;
tim++;
dfn[x]=low[x]=tim;
for (int i=0;i<son[x].size();i++){
int v=son[x][i];
if (!vis[v]) Tarjan(v);
if (vis[v]) low[x]=min(low[x],low[v]);
}
if (dfn[x]==low[x]) ans++;
}
int main() {
cin>>n>>m;
for (int i=1;i<=m;i++){
int x,y;
read(x);
read(y);
son[x].push_back(y);
}
for (int i=1;i<=n;i++)
if (!vis[i]) Tarjan(i);
for (int i=1;i<=n;i++)
cout<<low[i]<<' ';
cout<<endl;
cout<<ans<<endl;
return 0;
}
蒟蒻个人理解,有意见可以提。
上一篇: win10输入法只能打英文怎么解决
下一篇: QQ、微信、新浪微博和百度第三方登录
推荐阅读
-
[HDU-1269] SCC tarjan求强连通分量模板题
-
算法竞赛——进阶指南——acwing 367. 学校网络 SCC - tarjan求强连通+思维
-
程序设计思维 C - 班长竞选 (强连通分量、kosaraju算法)
-
Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量
-
无向连通图求割点割边tarjan算法
-
1027 - Tarjan之点双连通分量 - 矿场搭建[HNOI2012]
-
迷宫城堡【图之强连通】【tarjan模板】
-
Tarjan-强连通分量
-
算法竞赛——进阶指南——acwing 367. 学校网络 SCC - tarjan求强连通+思维
-
Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量