Kosaraju算法
借助反图获得好的dfs遍历顺序
int bel[maxn],stk[maxn],top,blocks;
bool vis[maxn];
vector<int>G1[maxn],G2[maxn];
inline void dfs1(int u)
{
if(vis[u]) return;
vis[u]=1;
for(int i=0;i<G1[u].size();i++){
dfs1(G1[u][i]);
}
stk[top++]=u;
return;
}
inline void dfs2(int u)
{
if(bel[u]) return;
bel[u]=blocks;
for(int i=0;i<G2[u].size();i++){
dfs2(G2[u][i]);
}
return;
}
inline void Kosaraju(int n)
{
for(int i=1;i<=n;i++) dfs1(i);
for(int i=n-1;i>=0;i--){
if(bel[stk[i]]) continue;
++blocks;
dfs2(stk[i]);
}
return;
}
Tarjan算法
借助时间戳+dfs,注意有向图dfs森林可能有横向边
struct E
{
int to,next;
}edge[maxm];
int head[maxn],tol;
inline void Addedge(int u,int v)
{
edge[tol].to=v;edge[tol].next=head[u];head[u]=tol++;
return;
}
int dfn[maxn],low[maxn],stk[maxn],bel[maxn],tot,top,blocks;
inline void Tarjan(int u)
{
dfn[u]=low[u]=++tot;
stk[top++]=u;
int v;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(!dfn[v]){
Tarjan(v);
if(low[v]<low[u]) low[u]=low[v];
}
else if(!bel[v]&&dfn[v]<low[u]) low[u]=dfn[v];
//bel[v]==0确保v在当前scc中
}
if(low[u]==dfn[u]){
++blocks;
do{
v=stk[--top];
bel[v]=blocks;
}while(v!=u);
}
return;
}
时间复杂度:O(n+m)