伪代码:
tarjan(u) { dfn[u]=low[u]=++index; //流水号 Stack.push(u); for(从u可达的每一个点v) { if(v未被访问过) { tarjan(v); low[u]=min(low[u],low[v]); } else if(v还在栈内) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { num_of_scc++; while(Stack.top()!=u) { 记录信息 st.pop(); } 记录信息 st.pop(); } }
模板:
输入格式: 第一行:n,m,分别为点数和边数(n<=100000) 接下来m行,每行两个整数x,y,表示从x到y有一条有向边 (1<=x,y<=n)
输出格式: 一个整数表示强连通分量的数量
#include <bits/stdc++.h> using namespace std; const int MAXN=100005; int n,m; vector<int> G[MAXN]; int dfn[MAXN],low[MAXN],cnt=0,index_=0; int scc[MAXN],size[MAXN]; bool inStack[MAXN]; stack<int> st; void tarjan(int u) { index_++; dfn[u]=index_; low[u]=index_; st.push(u); inStack[u]=true; for(int i=0;i<G[u].size();i++) { if(!dfn[G[u][i]]) { tarjan(G[u][i]); low[u]=min(low[u],low[G[u][i]]); } else if(inStack[G[u][i]]) low[u]=min(low[u],dfn[G[u][i]]); } if(low[u]==dfn[u]) { cnt++; while(st.top()!=u) { scc[st.top()]=cnt; size[cnt]++; inStack[st.top()]=false; st.pop(); } scc[st.top()]=cnt; size[cnt]++; inStack[st.top()]=false; st.pop(); } } int main() { ios::sync_with_stdio(0); //syn加速 cin>>n>>m; for(int i=0;i<m;i++) { int x,y; cin>>x>>y; G[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); cout<<cnt<<endl; return 0; }