首页 > 代码库 > 强连通分量tarjan模板复习

强连通分量tarjan模板复习

对于一个有向图定点的子集,在该子集中任取两点u与v,都能找到一条从u到v的路径,则称该子集是强连通的。若该集合加入到任意点集中,它都不再强连通,则称这个子集是原图的一个强连通分量。任意一张图都可以分解成若干个不相交的强连通分量。这是强连通分量分解。把分解后的强连通分量缩成一个顶点,就可以得到一个有向无环图。

如图:技术分享

 

求一张图的强连通分量的个数,常用tarjan算法,它是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

模板如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int n,m;
 8 struct node{
 9     int fr,to;
10 }ed[50001];
11 bool vis[10001];
12 int dfs[10001],stack[10001],head[10001],low[10005];
13 int tot=0,ans=0,in=0,num=0;
14 void add(int u,int v){
15     ed[++num].fr=head[u];head[u]=num;ed[num].to=v;
16 }
17 void tarjan(int x){
18     dfs[x]=low[x]=++tot;
19     stack[++in]=x;
20     vis[stack[in]]=1;
21     int i;
22     for(i=head[x];i;i=ed[i].fr){
23         if(!dfs[ed[i].to]){
24             tarjan(ed[i].to);
25         }
26         if(vis[ed[i].to]){
27             low[x]=min(low[x],low[ed[i].to]);
28         }
29     }
30     if(low[x]==dfs[x]){
31         for(++ans;stack[in+1]!=x;)  vis[stack[in--]]=0;
32     }
33 }
34 int main(){
35     scanf("%d%d",&n,&m);
36     int i;
37     for(i=1;i<=m;i++){
38         int x,y;
39         scanf("%d%d",&x,&y);
40         add(x,y);
41     }
42     for(i=1;i<=n;i++)  if(!dfs[i])  tarjan(i);
43     printf("%d\n",ans);
44     return 0;
45 }

 

强连通分量tarjan模板复习