Tarjan求强连通分量问题
塔杨算法的前提是:图为有向图。
强连通;强连通图;极大连通子图(强连通分量)。
实现方法:
dfn[i]:dfs遍历第i个点的次序(时间戳)。
low[i]:还在栈中的可以到达i的最小的时间戳。(按从栈顶到栈底的顺序,i点所能到达的最早的点)
stack[ ]:存放当前遍历过但还没有确定其所属的连通分量的点。
当下一个点已经在栈中:
证明从在栈中下一个点到该点都为一个连通分量。
因为每一个连通分量只需要一个点来代表他,所以除了最前面的点dfn[i] == low[i],其他点dfn[i] != low[i]。
#include<bits/stdc++.h> using namespace std; const int Maxn=100005; int next[Maxn]; int ans[Maxn]; int head[Maxn],cnt; struct road { int to,next; }e[Maxn*2]; void add(int a,int b) { cnt++; e[cnt].to=b; e[cnt].next=head[a]; head[a]=cnt; } int sum,color[Maxn],low[Maxn],ins[Maxn],tim[Maxn],sta[Maxn],top=1,col; int Lemon[Maxn]; void Tarjan(int x) { sum++; tim[x]=low[x]=sum; sta[top]=x; top++; ins[x]=1; for(int i=head[x];i!=0;i=e[i].next) { if(ins[e[i].to]==0) { Tarjan(e[i].to); low[x]=min(low[x],low[e[i].to]); } else if(ins[e[i].to]==1) low[x]=min(low[x],tim[e[i].to]); } if(tim[x]==low[x]) { col++; do { top--; color[sta[top]]=col; ins[sta[top]]=-1; }while(sta[top]!=x); } return ; } void search(int root,int x,int step) { if(ans[x]!=0) { ans[root]=ans[x]+1; return ; } else { search(x,next[x],step+1); ans[root]=ans[x]+1; } } int main() { int n; cin>>n; for(int i=1;i<=n;i++) { scanf("%d",&next[i]); add(i,next[i]); if(next[i]==i) ans[i]=1;//注意特判环为1的情况。 } for(int i=1;i<=n;i++) if(ins[i]==0) Tarjan(i); for(int i=1;i<=n;i++) Lemon[color[i]]++;//记录环的大小 for(int i=1;i<=n;i++) if(Lemon[color[i]]!=1) ans[i]=Lemon[color[i]];//处理在环内的点 for(int i=1;i<=n;i++) if(ans[i]==0) search(i,next[i],1);//处理在环外的点。 for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }