1. 程式人生 > >【圖論】求無向連通圖的割點

【圖論】求無向連通圖的割點

1. 割點與連通度

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

關節點和重連通圖在實際中較多應用。顯然,一個表示通訊網路的圖的連通度越高,其系統越可靠,無論是哪一個站點出現故障或遭到外界破壞,都不影響系統的正常工作;又如,一個航空網若是重連通的,則當某條航線因天氣等某種原因關閉時,旅客仍可從別的航線繞道而行;再如,若將大規模的積體電路的關鍵線路設計成重連通的話,則在某些元件失效的情況下,整個片子的功能不受影響,反之,在戰爭中,若要摧毀敵方的運輸線,僅需破壞其運輸網中的關節點即可。

簡單的例子

(a)中G7 是連通圖,但不是重連通圖。圖中有三個關節點A、B 和G 。若刪去頂點B 以及所有依附頂點B 的邊,G7 就被分割成三個連通分量{A、C、F、L、M、J}、{G、H、I、K}和{D、E}。類似地,若刪去頂點A 或G 以及所依附於它們的邊,則G7 被分割成兩個連通分量。

2. 求割點的方法

暴力的方法:

  • 依次刪除每一個節點v
  • 用DFS(或BFS)判斷還是否連通
  • 再把節點v加入圖中

若用鄰接表(adjacency list),需要做\(V\)次DFS,時間複雜度為\(O(V*(V+E))\)。(題外話:我在面試實習的時候,只想到暴力方法;面試官提示只要一次DFS就就可以找到割點,當時死活都沒想出來)。

有關DFS搜尋樹的概念

在介紹演算法之前,先介紹幾個基本概念

  • DFS搜尋樹:用DFS對圖進行遍歷時,按照遍歷次序的不同,我們可以得到一棵DFS搜尋樹,如圖(b)所示。
  • 樹邊:(在[2]中稱為父子邊),在搜尋樹中的實線所示,可理解為在DFS過程中訪問未訪問節點時所經過的邊。
  • 回邊:(在[2]中稱為返祖邊後向邊),在搜尋樹中的虛線所示,可理解為在DFS過程中遇到已訪問節點時所經過的邊。

基於DFS的演算法

該演算法是R.Tarjan發明的。觀察DFS搜尋樹,我們可以發現有兩類節點可以成為割點:

  1. 對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u為割點;
  2. 對非葉子節點u(非根節點),若其子樹的節點均沒有指向u的祖先節點的回邊,說明刪除u之後,根結點與u的子樹的節點不再連通;則節點u為割點。

對於根結點,顯然很好處理;但是對於非葉子節點,怎麼去判斷有沒有回邊是一個值得深思的問題。

我們用dfn[u]記錄節點u在DFS過程中被遍歷到的次序號,low[u]記錄節點u或u的子樹通過非父子邊追溯到最早的祖先節點(即DFS次序號最小),那麼low[u]的計算過程如下:

\[ low[u] = \left \{ { \matrix { { \min \{ low[u],\ low[v]\} } & {(u,v)為樹邊} \cr { \min \{ low[u],\ dfn[v]\} } & {(u,v)為回邊且v不為u的父親節點} \cr } } \right. \]

下表給出圖(a)對應的dfn與low陣列值。

i 0 1 2 3 4 5 6 7 8 9 10 11 12
vertex A B C D E F G H I J K L M
dfn[i] 1 5 12 10 11 13 8 6 9 4 7 2 3
low[i] 1 1 1 5 5 1 5 5 8 2 5 1 1

對於情況2,當(u,v)為樹邊且low[v] >= dfn[u]時,節點u才為割點。該式子的含義:以節點v為根的子樹所能追溯到最早的祖先節點要麼為v要麼為u。

程式碼實現

void dfs(int u) {
    //記錄dfs遍歷次序
    static int counter = 0; 
    
    //記錄節點u的子樹數
    int children = 0;
    
    ArcNode *p = graph[u].firstArc;
    visit[u] = 1;

    //初始化dfn與low
    dfn[u] = low[u] = ++counter;

    for(; p != NULL; p = p->next) {
        int v = p->adjvex;
        
        //節點v未被訪問,則(u,v)為樹邊
        if(!visit[v]) {
            children++;
            parent[v] = u;
            dfs(v);
            low[u] = min(low[u], low[v]);
            //case (1)
            if(parent[u] == NIL && children > 1) {
                printf("articulation point: %d\n", u);
            }
            //case (2)
            if(parent[u] != NIL && low[v] >= dfn[u]) {
                printf("articulation point: %d\n", u);
            }
        }

        //節點v已訪問,則(u,v)為回邊
        else if(v != parent[u]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

採用鄰接表儲存圖,該演算法的時間複雜度應與DFS相同,為\(O(V+E)\)

3. 參考資料

相關推薦

連通

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

連通

1. 割點與連通度 在無向連通圖中,刪除一個頂點v及其相連的邊後,原圖從一個連通分量變成了兩個或多個連通分量,則稱頂點v為割點,同時也稱關節點(Articulation Point)。一個沒有關節點的連通圖稱為重連通圖(biconnected graph)。若在連通圖上

連通的最小生成樹(c語言版)

完整原始碼地址:[email protected]:hglspace/MinCostSpTree.git 圖例:                     1 普里姆演算法 /*  普里姆演算法:假設N={v,{E}}是連通圖,TE是N上的最小生成樹中邊的集合

連通的最小詳解以及java原始碼實現

import java.util.*; /**尋找割點*/ public class FindArt { static class Node { Node(String name) { this.name=name; Childen=new Arra

用Tarjan演算法連通&&

/** 割點割邊挺好理解的,割點就是一個無向連通圖,把其中一個點 挖掉剩下的圖不連通,割邊就是把一條邊砍掉不連通 比如:有一個通訊網路,要求一顆炸彈,把這個通訊網路搞得不連通,問 炸哪個點或哪條邊。 Tarjan 演算法實現求割邊

XSY1295calc n個n條邊連通計數 prufer序列

ring pre end ctime 節點 splay 按順序 sin algorithm 題目大意   求\(n\)個點\(n\)條邊的無向連通圖的個數   \(n\leq 5000\) 題解   顯然是一個環上有很多外向樹。   首先有一個東西:\(n\)個點選\(k\

ZSTU4213 2015年12月浙理工校賽 D連通分量tarjan演算法One-Way Roads 連通確定邊的方向使得全任意兩點間可達

4213: One-Way Roads Time Limit:1 Sec  Memory Limit:128 MB  Special JudgeSubmit:133  Solved:45 Description In the ACM kingdom, there a

[帶標號連通計數 容斥原理 多項式逆 多項式ln 模板題] BZOJ 3456 城市規劃

可以通過容斥求出答案的表示式fi=2C2i−∑j=1i−1Cj−1i−1∗fj∗2C2i−j 其中前一部分表示i個點任意連邊 後半部分列舉1所在的連通塊然後容斥掉 ∑j=1ifj(j−1)!∗2C2i−j(i−j)!=2C2i(i−1)! 這是個卷積的

poj1523 SPF 連通 關節點 tarjan演算法

SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5103 Accepted: 2347 Description Consider the two networks shown below.

leetcode 847. Shortest Path Visiting All Nodes 連通遍歷最短路徑

sel shu turn 判斷 lam 最短 額外 動態 訪問 設計最短路徑 用bfs 天然帶最短路徑 每一個狀態是 當前的階段 和已經訪問過的節點 下面是正確但是超時的代碼 class Solution: def shortestPathLength(self,

LeetCode 547. 朋友圈數量--連通

解析 方法一:DFS 遍歷所有人,對於每一個人,尋找他的好友,找到好友後再找這個好友的好友,這樣深度優先遍歷下去,設定一個visited記錄是否已經遍歷了這個人。 因為如果m個人最多m個朋友圈,設定後visited後,相同的朋友圈會檢測到visited[i]!=0就會不算數

連通中兩點間所有路徑的演算法

http://bbs.csdn.net/topics/360001583 之前在csdn就這個問題發帖求教過,過了幾天沒看到回覆就沒再關心。後來自己設計了一個演算法,在公司的專案中實踐了一下,效果還可以,貼出來供大家參考。演算法要求:1. 在一個無向連通圖中求出兩個給

poj1737 Connected Graph(n連通

題目連結 題目描述: 給出n個點,求n個點的無向連通圖 分析: 巨坑啊 經典題目,有兩種方法: 總方案數-不合法方案 nn個點的完全圖有C(n,2)=n(n−1)2C(n,2)=n(n

資料結構 之 連通

下列關於無向連通圖特性的敘述中,正確的是 Ⅰ.所有頂點的度之和為偶數Ⅱ.邊數大於頂點個數Ⅲ.至少有一個頂點的度為1 如下圖所示為一個無向連通圖:任何兩個節點之前都是連通的,都存在一條路徑,並且圖中沒有方向。        (1)頂點的度為頂點所連線的邊的個數,無向連通圖中的

面試題連結串列的環入口

環入口點:我們設A是連結串列的起點,B是環的入口點,C是環內快慢指標的相遇點。兩個快慢指標定義為slow和fast. slow走的路程:A->B->C; fast走的路程:A->B->C->B->C; 2*(x+y)=x+y+z+y 

的拓撲排序

1. 引言 有向無環圖(Directed Acyclic Graph, DAG)是有向圖的一種,字面意思的理解就是圖中沒有環。常常被用來表示事件之間的驅動依賴關係,管理任務之間的排程。拓撲排序是對DAG的頂點進行排序,使得對每一條有向邊(u, v),均有u(在排序記錄中)比v先出現。亦可理解為對某點v而言,只

Light OJ - 1026 - Critical Links(-Tarjan算法的橋數) - 帶詳細註釋

tdi lan [] spl 頂點 ace 開始 else lose   原題鏈接   無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋。   也可以先用Tajan()進行dfs算出所有點 的low和dfn值,並記錄dfs過程中每個 點的父節點;然後再把所有點

___連通分量個數

求無向圖連通分量個數方法:    基於DFS,從某一頂點出發遍歷圖,for迴圈,改變起始頂點,count計數。 程式碼如下: void DFSTraverse(ALGraph G){ //深度遍歷圖 void DFS(ALGraph G,

poj 1523 所有以及刪除連通分量個數 給出詳細演算法思路

題意 無向圖找出每個割點,然後求出刪除這個割點所得的連通分量個數 節點編號在1-1000,但沒說按順序給出 思路 無向圖求所有割點是一類經典問題,這篇blog就以這題為例簡單介紹一下求解的演算法思路 我們希望在O(n+m)的時間裡求出所有的割

單源最短路模板(有)Dijkstra

#include <cstdio> #include <iostream> #include <cstring> #include <queue> #in