图论 —— 图的连通性 —— Tarjan 求强连通分量
【概述】
Tarjan 算法是基于對圖深度優先搜索的算法,每個強連通分量為搜索樹中的一棵子樹。
搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以判斷棧頂到棧中的節點是否為一個強連通分量。
【基本思路】
定義 DFN(u) 為節點 u 搜索的次序編號(時間戳),即是第幾個被搜索到的,Low(u) 為 u 或 u 的子樹能夠追溯到的最早的棧中節點的次序號。
每次找到一個新點 i,有:DFN(i)=low(i)
當點 u?與點 v 相連時,如果此時(時間為 DFN[u] 時)v不在棧中,u 的 low 值為兩點的 low 值中較小的一個
即:low[u]=min(low[u],low[v])
當點 u 與點 v 相連時,如果此時(時間為 DFN[u] 時)v 在棧中,u 的 low 值為 u 的 low 值和 v 的 dfn 值中較小的一個
即:low[u]=min(low[u],dfn[v])?
當 DFN(u)=Low(u) 時,以 u 為根的搜索子樹上所有節點是一個強連通分量。
【流程】
以下圖為例,共有三個強連通分量:1234、5、6
從節點 1 開始 DFS,把遍歷到的節點加入棧中,搜索到節點 u=6 時,DFN[6]=LOW[6]=4,找到了一個強連通分量 {6}
返回節點 5,發現 DFN[5]=LOW[5]=3,退棧后 {5} 為一個強連通分量。
返回節點 3,繼續搜索到節點 4,把 4 加入堆棧。發現節點 4 像節點 1 的后向邊,節點 1 還在棧中,所以 LOW[4]=1。節點 6 已經出棧,不再訪問 6,返回 3,(3,4) 為樹枝邊,所以 LOW[3]=LOW[4]=1。
繼續回到節點 1,最后訪問節點 2。訪問邊 (2,4),4 還在棧中,所以 LOW[2]=4。返回 1 后,發現 DFN[1]=LOW[1],把棧中節點全部取出,組成一個連通分量 {1,3,4,2}。
至此,算法結束。經過該算法,求出了圖中全部的三個強連通分量{1,3,4,2}、{5}、{6}。
【時間復雜度】
通過上述流程分析,運行 Tarjan 算法的過程中,每個頂點都被訪問了一次,且只進出了一次堆棧,每條邊也只被訪問了一次,所以該算法的時間復雜度為 O(N+M)。
【實現】
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stack> #include<vector> #define N 20001 using namespace std; int n,m; vector<int> G[N]; stack<int> S; int dfn[N],low[N]; bool vis[N];//標記數組 int sccno[N];//記錄結點i屬于哪個強連通分量 int block_cnt;//時間戳 int sig;//記錄強連通分量個數 void Tarjan(int x){vis[x]=true;dfn[x]=low[x]=++block_cnt;//每找到一個新點,紀錄當前節點的時間戳S.push(x);//當前結點入棧for(int i=0;i<G[x].size();i++){//遍歷整個棧int y=G[x][i];//當前結點的下一結點if(vis[y]==false){//若未被訪問過Tarjan(y);low[x]=min(low[x],low[y]);}else if(!sccno[y])//若已被訪問過,且不屬于任何一個連通分量low[x]=min(low[x],dfn[y]);}if(dfn[x]==low[x]){//滿足強連通分量要求sig++;//記錄強連通分量個數while(true){//記錄元素屬于第幾個強連通分量int temp=S.top();S.pop();sccno[temp]=sig;if(temp==x)break;}} } int main() {while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<n;i++)G[i].clear();while(m--){int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);}sig=0;block_cnt=0;memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(sccno,0,sizeof(sccno));for(int i=0;i<n;i++)if(vis[i]==false)Tarjan(i);for(int i=0;i<n;i++)printf("%d號點屬于%d分量\n",i,sccno[i]);} }總結
以上是生活随笔為你收集整理的图论 —— 图的连通性 —— Tarjan 求强连通分量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 彩灯(洛谷-P3857)
- 下一篇: 图论 —— 图的遍历 —— 欧拉通路与欧