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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

tarjan对有向图的缩点(求强连通分量)

發布時間:2024/9/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tarjan对有向图的缩点(求强连通分量) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

tarjan對有向圖的縮點(求強聯通分量)


0x00 tarjan算法簡介

tarjan算法是基于DFS的算法,核心在于巧妙的使用訪問節點的時間戳 和 棧。
tarjan算法可以用于求解:

  • 最近公共祖先(LCA);
  • 有向圖的強連通分量;
  • 無向圖的雙連通分量;
  • 割點;
  • 橋;

本篇只介紹用tarjan算法來求解有向圖的強連通分量。
強連通分量:當中任意兩個節點互相可達(如果只有一個節點,這一個節點也是強連通分量)

基本思想:

定義兩個數組low[],dfn[],

dfn[i]:記錄訪問節點i時的次序(時間戳);

low[i]:節點i可以追溯到的最小的時間戳;

dfs訪問節點,

訪問節點i時初始化: low[i] = dfn[i] = 訪問編號,同時讓節點i入棧,并標記i已經入棧

在訪問節點過程中,會不斷更新low[]數組,當在回溯過程中發現low[i]==dfn[i]時,

說明此時形成了一個強連通分量,進行出棧操作(可進行染色標記這些節點屬于強連通),

出棧元素等于此時的根節點后,停止出棧(元素出棧時,要記得標記已經出棧)。繼續dfs。

下面來大概模擬一下下方這張圖:


假設從1號節點開始dfs訪問節點:

low[1] = dfn[1] = 1
stack = {1}
low[2] = dfn[2] = 2
stack = {1,2}
low[4] = dfn[4] = 3
stack = {1,2,4}

此時在4號節點,這里假設之后訪問1號節點,
(當然之后也可能先訪問5,最后結果是一樣的)
發現1號節點已經在訪問過(在棧中),
那么此時的4號節點的就可以更新,追溯最小的編號:
low[4] = min(low[4],dfn[1]) = 1。

繼續dfs:
low[5]=dfn[5] = 4
stack = {1,2,4,5}
low[3] = dfn[3] = 5
stack = {1,2,4,5,3}

根節點在3,沒有節點可以訪問了,遞歸返回:
發現:low[3] = dfn[3]:
stack中元素出棧(染色進行標記),出棧元素等于此時的根節點后,停止出棧。
此時出棧的只有:3
{3}是一個強連通分量;
stack = {1,2,4,5}

繼續 遞歸返回到 5:
low[5] = min(low[5],low[3]) = min(4,5) = 4
出現了:low[5] = dfn[5]
stack中元素出棧(染色進行標記),出棧元素等于此時的根節點后,停止出棧。
此時出棧的只有:5
{5}也是一個強連通分量;
stack = {1,2,4}

繼續 遞歸返回到 4:
low[4] = min(low[4],low[5]) = min(1,4) = 1
low[4] != dfn[4]

繼續 遞歸返回到 2:
low[2] = min(low[2],low[4]) = min(2,1) = 1
low[2] != dfn[2]

繼續 遞歸返回到 1:
low[1] = min(low[1],low[2]) = min(1,1) = 1
出現了:low[1] == dfn[1]
stack中元素出棧(染色進行標記),出棧元素等于此時的根節點后,停止出棧。
{4,2,1}是一個強連通分量。
stack = {}

最終的強連通分量分別為:{3},{5},{4,2,1}


(…具體看下面代碼,自己手動模擬一遍就能夠懂,不好畫圖,文字表述實在辛苦。。)


0x01題目

洛谷p2863
有一個 n個點,m 條邊的有向圖,請求出這個圖點數大于 1 的強聯通分量個數。


0x02代碼

#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 5e4+5; const int P = 1e4+5; int n,m; struct Edge {int from;int to;int next; }edge[N]; int head[N],id; int low[P]; int dfn[P]; int st[P]; bool vis[P]; int top; int color[P]; int dfn_num; int color_num; int ans; inline void add_edge(int from,int to) {edge[id].from = from;edge[id].to = to;edge[id].next = head[from];head[from] = id++; } void init() {memset(head,-1,sizeof(head));id = 0; } void tarjan(int u) {st[++top] = u;vis[u] = true;dfn[u] = ++dfn_num;low[u] = dfn_num;for(int i = head[u]; ~i; i = edge[i].next){int to = edge[i].to;if(!dfn[to]){tarjan(to);low[u] = min(low[u],low[to]);}else if(vis[to])low[u] = min(low[u],dfn[to]);}if(dfn[u] == low[u]){color[u] = ++color_num;int cnt = 1;vis[u] = false;while(st[top] != u){color[st[top]] = color_num;cnt++;vis[st[top--]] = false;}ans += cnt > 1;top--;} } int main() {cin>>n>>m;init();while(m--){int a,b;cin>>a>>b;add_edge(a,b);}for(int i = 1; i <= n; i++)if(!dfn[i]) tarjan(i);cout<<ans<<endl;return 0; }

總結

以上是生活随笔為你收集整理的tarjan对有向图的缩点(求强连通分量)的全部內容,希望文章能夠幫你解決所遇到的問題。

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