日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图论 —— 图的连通性 —— Tarjan 求强连通分量

發布時間:2025/3/17 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图论 —— 图的连通性 —— 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 求强连通分量的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。