1. 程式人生 > >Tarjan演算法求解一個無向圖中的割點和橋問題

Tarjan演算法求解一個無向圖中的割點和橋問題

基本概念

割點:Articulation Point
在無向連通圖中,刪除一個頂點v及其相連的邊後,原圖從一個連通分量變成了兩個或多個連通分量,則稱頂點v為割點,同時也稱關節點(Articulation Point)。
雙連通的圖:一個沒有關節點的連通圖稱為重連通圖(biconnected graph)(雙連通圖)。
連通度:k,若在連通圖上至少刪去k 個頂點才能破壞圖的連通性。

演算法應用

演算法應用:通訊網路中,用來衡量系統可靠性,連通度越高,可靠性越高。

求解方法

  1. 暴力求解,依次刪除每一個節點v,用DFS(或者BFS)判斷是否連通,再把節點加入圖中。若用鄰接表(adjacency list),需要做V次DFS,時間複雜度為O(V∗(V+E))O(V∗(V+E))
  2. Jarjan演算法,只用一次DFS求解。

第一個方法不多說:
對於第二個方法
我們要維持兩個資料結構:
dfn[u]:記錄節點u在DFS過程中被遍歷到的次序號。
low[u]:記錄節點u或u的子樹通過非父子邊追溯到最早的祖先節點(即DFS次序號最小)。
其中對於low[u]的理解是這樣的:當(u,v)為樹邊時,且v沒有被訪問過,則low[u]是min(low[u]和low[v])。當v被訪問過,如果v不是u的父節點(如果是則說明有重邊,不考慮),則(u,v)為回邊,則low[u]取min(low[u], dfn[v])。
這裡寫圖片描述
這裡寫圖片描述

程式碼思路解析

#include<iostream>
#include<vector> #include<fstream> using namespace std; #define N 201 vector<int>G[N]; bool visit[N]; int dfn[N]; int low[N]; int parent[N]; int min(int a, int b) { if (a < b) return a; else return b; } void input() { int n, m;//分別表示頂點數和邊數 ifstream in("input.txt"); in >> n >> m; int
a, b; for (int i = 1; i <= m; ++i) { in >> a >> b; G[a].push_back(b);/*鄰接表儲存無向邊*/ G[b].push_back(a); } } void dfs(int u) { //記錄dfs遍歷次序 static int counter = 0; //記錄節點u的子樹數 int children = 0; visit[u] = true; //初始化dfn與low dfn[u] = low[u] = ++counter; for (int j = 0; j < G[u].size(); j++)//遍歷與u相連的頂點 { int v = G[u][j]; if (!visit[v]) { children++; parent[v] = u;//u是v的父節點 dfs(v);//深度優先搜尋v low[u] = min(low[u], low[v]);//等v完成深度優先搜尋之後,low[u]記錄節點u或u的子樹通過非父子邊追溯到最早的祖先節點(即DFS次序號最小) if (parent[u] == -1 && children > 1)//對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u為割點; { cout << "1 articulation point: " << u<<endl; } if (parent[u] != -1 && low[v] >= dfn[u])//對非葉子節點u(非根節點),若其子樹的節點均沒有指向u的祖先節點的回邊(條件low[v] >= dfn[u]表達的就是),說明刪除u之後,根結點與u的子樹的節點不再連通;則節點u為割點。 { cout << "2 articulation point: " << u << endl; //這樣做,可能出現某個頂點多次輸出,其實可以用一個指示變數來指示,做到頂點不重複輸出 } if (low[v] >dfn[u]) //橋的條件 { cout << "Bridge " << v << " " << u << endl; } } else if (v != parent[u]) {//節點v已訪問,則(u,v)為回邊,且不是重邊 low[u] = min(low[u], dfn[v]); } } } int main() { /*input(); memset(dfn, -1, sizeof(dfn)); memset(father, 0, sizeof(father)); memset(low, -1, sizeof(low)); memset(is_cut, false, sizeof(is_cut)); count();*/ memset(dfn, -1, sizeof(dfn)); memset(low, -1, sizeof(low)); memset(visit, false, sizeof(visit)); memset(parent, -1, sizeof(parent)); input(); dfs(1); system("pause"); return 0; }

這裡寫圖片描述

參考