Tarjan算法——强连通分量
´Tarjan算法是一个通过对图进行深度优先搜索并通过同时维护一个栈以及两个相关时间戳的算法。
´定义dfn(u)表示节点u搜索的次序编号(时间戳,第几个搜索的节点),low(u)表示节点u或u的子树当中可以找到的最早的栈中的节点的时间戳。
´由定义,我们可以得到:
´Low(u)=dfn(u),
´low(u)=min(low(u),low(v))当(u,v)为搜索树当中的树枝边。
´low(u)=min(low(u),dfn(v))当(u,v)为搜索树当中的后向边(也就是v仍在栈内的情况)
´每当找到一个节点在遍历完后返回时low(u)=dfn(u),那么可以弹出栈中u以上的所有节点,此时这里的所有节点形成一个强连通分量
缩点操作:
´当我们在求出强连通分量之后,我们可以把同一个强连通分量里的点当成新图里的一个新点,然后如果原图中两个不在同一个强连通分量的点有连边的话,那么他们所对应的新点也有连边。
´我们可以知道,新图一定是一个有向无环图。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100000+15; 5 const int maxm=100000+15; 6 struct Edge 7 { 8 int x,y,next; 9 Edge(int x=0,int y=0,int next=0):x(x),y(y),next(next) {} 10 }edge[maxm]; 11 int sumedge,head[maxn]; 12 int n,m; 13 int ins(int x,int y) 14 { 15 edge[++sumedge]=Edge(x,y,head[x]); 16 return head[x]=sumedge; 17 } 18 int tim,dfn[maxn],low[maxn],Stack[maxn],top,color[maxn],sumc; 19 int state[maxn]; 20 int dfs(int now) 21 { 22 state[now]=1; 23 dfn[now]=++tim; 24 low[now]=dfn[now]; 25 Stack[++top]=now; 26 for (int u=head[now];u;u=edge[u].next) 27 if (state[edge[u].y]==0) 28 { 29 dfs(edge[u].y); 30 low[now]=min(low[now],low[edge[u].y]); 31 } 32 else 33 if (state[edge[u].y]==1) 34 low[now]=min(low[now],dfn[edge[u].y]); 35 if (dfn[now]==low[now]) 36 { 37 sumc++; 38 for (;Stack[top]!=now;top--) 39 { 40 color[Stack[top]]=sumc; 41 state[Stack[top]]=2; 42 } 43 color[now]=sumc; 44 state[now]=2; 45 top--; 46 } 47 return 0; 48 } 49 int main() 50 { 51 scanf("%d%d",&n,&m); 52 for (int i=1;i<=m;i++) 53 { 54 int x,y; 55 scanf("%d%d",&x,&y); 56 ins(x,y); 57 } 58 dfs(1); 59 for (int i=1;i<=n;i++) printf("%d ",color[i]); 60 printf("\n"); 61 return 0; 62 }