1. 程式人生 > >演算法五:圖的割點和橋

演算法五:圖的割點和橋

一、定義
圖的割點
一個無向連線圖中,如果刪除某個頂點後,圖不再連同(即任意兩點之間不能互相到達) ,稱這樣的頂點為割點
或:某個點是割點當且僅當刪除該點和與該點相關聯的邊後圖變得不連通。

圖的割邊/橋: 
一個無向連通圖中,如果刪除某條邊後,圖不再連通,這條邊就為割邊。
或:某條邊是割邊當且僅當刪除該邊後圖變的不連通。

二.求割點,橋
 使用dfs(深搜)來求割點和橋。先明確一下幾點:
1、  圖的dfs相當於是對相應的dfs樹的遍歷。
2、  無向圖的dfs樹,無論以哪個點為根都可以遍歷完所有的點。
3、  無向圖的dfs樹,沒有橫叉邊(連線兩個子樹的邊)。

對原圖進行深度優先搜尋,會生成一顆深度優先搜尋生成樹。定義dfs[u]為u在深度
優先搜尋生成樹中被遍歷到的序號,low[u]為u或者他的子樹中可以通過非父子邊追
溯到的最早結點。

①一個頂點是割點,滿足下列條件之一:

1).u是樹根,u有兩個或兩個以上的分支/u有多於一個子樹;
2).u不是樹根,且滿足存在(u,v)為樹枝邊(或稱父子邊,即u為v在搜尋樹中的父親),(u,v)是樹邊且low[v]>=dfn[u]。
low(u)=min{dfn(u),low(v) if(u,v)是樹枝邊/父子邊,dfn(v) if(u,v)是後向邊/返祖邊}

②橋無向邊(u,v),當且僅當(u,v)為樹枝邊,且滿足dfn[u]<low[v]。
注:1、為方便程式編寫,我們都採用low[v]來判斷u。(理論上low[u]也可以判斷割點)

三、程式設計

準備兩個陣列low和dfn。
Low陣列是一個標記陣列,記錄該點所在的強連通子圖所在搜尋子樹的根節點的Dfn值(很繞嘴,往下看你就會明白)。
dfn陣列記錄搜尋到該點的時間,也就是第幾個搜尋這個點的。根據以下幾條規則,經過搜尋遍歷該圖(無需回溯)和對棧的操作,我們就可以得到該有向圖的強連通分量。

1.陣列的初始化:當首次搜尋到點p時,dfn與low陣列的值都為到該點的時間。
2.堆疊:每搜尋到一個點,將它壓入棧頂。
3.當點p有與點p’相連時,如果此時(時間為dfn[p]時)p’在棧中(是父子邊),p的low值為min(low(p),dfn(p’) )。
4.當點p有與點p’相連時,如果此時(時間為dfn[p]時)p’不在棧中(是後向邊),p的low值為min(low(p),low(p’))。
5.每當搜尋到一個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成一個強連通分量。
6.繼續搜尋(或許會更換搜尋的起點,因為整個有向圖可能分為兩個不連通的部分),直到所有點被遍歷。

      由於每個頂點只訪問過一次,每條邊也只訪問過一次,我們就可以在O(n+m)的時間內求出有向圖的強連通分量。

四、應用 

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