來一道裸代碼。
輸入:
一個圖有向圖。
輸出:
它每個強連通分量。
這個圖就是剛才講的那個圖。一模一樣。
input:
6 8
1 3
1 2
2 4
3 4
3 5
4 6
4 1
5 6
output:
6
5
3 4 2 1
代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<algorithm> #include<map> #define maxn 200005 using namespace std; struct node { int v,next; //v表示指向的點 next表示 }mp[1005]; int DFN[1005],LOW[1005]; //DFN[]作為這個點搜索的次序編號(時間戳) //LOW[]作為每個點在這顆樹中的,最小的子樹的根,每次保證最小,like它的父親結點的時間戳這種感覺 int stack[1005],heads[1005],visit[1005],cnt,tot,index; // 棧 訪問順序 是否訪問 void add(int x,int y) { mp[++cnt].next=heads[x]; mp[cnt].v=y; heads[x]=cnt; return ; } void tarjan(int x) { DFN[x]=LOW[x]=++tot; //初始化x stack[++index]=x; //進棧 visit[x]=1; //表示x已經入棧 for(int i=heads[x];i!=-1;i=mp[i].next){ if(!DFN[mp[i].v]) //如果沒有被訪問 { tarjan(mp[i].v); //往下延伸就是遞歸 LOW[x]=min(LOW[x],LOW[mp[i].v]); //遞歸出來,比較誰是誰的兒子/父親,就是樹的對應關系,涉及到強連通分量子樹最小根的事情 } else if(visit[mp[i].v]) //如果訪問過,並還在棧里 { LOW[x]=min(LOW[x],DFN[mp[i].v]); //比較誰是誰的兒子/父親。就是鏈接對應關系 } } if(LOW[x]==DFN[x]){ //發現整個連通分量子樹里的最小根 while(1) { cout<<stack[index]<<" "; visit[stack[index]]=0; index--; if(x==stack[index+1]) break; //出棧,並且輸出 } cout<<endl; } } int main() { memset(heads,-1,sizeof(heads)); int n,m; cin>>n>>m; int x,y; for(int i=1;i<=m;i++) { cin>>x>>y; add(x,y); } for(int i=1;i<=n;i++) { if(!DFN[i])tarjan(i); //當這個點沒有訪問過,就從這個點開始,防止圖沒有走完 } return 0; }
還有各大理解網站: (雜着看,就可以看懂)
http://blog.miskcoo.com/2016/07/tarjan-algorithm-strongly-connected-components
https://blog.csdn.net/mengxiang000000/article/details/51672725
https://www.cnblogs.com/yxysuanfa/p/7396057.html