1. 程式人生 > >無向圖求點割集演算法

無向圖求點割集演算法

黑書上給出了關於求點割集的演算法,但是比較模糊,我查閱了網路上的相關資料,理解了求點割集的過程,寫出如下求點割集的程式碼,並寫了一些簡單的證明.

割點集的定義:如果在連通圖G中去掉某一點後圖不連通,那麼這個點即為G的割點,所有割點的集合即為點割集。

求點割集的方法:利用tarjan演算法的思想,用陣列dfn[v]儲存DFS遍歷到點v的時間,陣列low[v]儲存點v能追溯到最早的祖先節點。

如果對於點v來說有如下結論:

1.如果點v是DFS序列的根節點,則如果v有一個以上的孩子,則v是一個割點。

2.如果v不是DFS序列根節點,並且點v的任意後繼u能追溯到最早的祖先節點low[u]>=dfn[v],則v是一個割點。

證明1:

       假設DFS遍歷的第一個節點v不是割點,那麼則有low[v]=dfn[v]=1,繼續對v的孩子節點u遍歷,必然有low[u]>=dfn[v],按照第二條性質,則v是割點,但我們已經假設v不是割點。這是由於v是DFS遍歷的起始節點,在遍歷序列中v沒有祖先節點,v的所有後繼節點能追溯到最早的祖先節點最多也就是v了,不可能比v再早了,因此必須把DFS遍歷的第一個節點v單獨考慮,那麼怎麼判斷v是不是割點呢?

      例如上圖,設v是DFS序列訪問的第一個節點,對v的孩子節點u和u的所有孩子節點進行DFS遍歷並標記為已經訪問後,如果v的另一個孩子節點k沒有被標記為已經訪問,那麼u和k之間一定不存在邊,也就是說u和k之間的連通必然需要點v,因此如果v是DFS遍歷的第一個節點,對v是否為割點的判斷方法是:看v是不是有多個孩子,如果有則v是割點。

證明2:

      如果v不是DFS遍歷的第一個節點,那麼對於v的所有後繼節點來說,如果v不是割點(也就是如果刪掉點v,剩下的圖還是連通圖),那麼v的後繼節點必然能追溯到DFS遍歷序列中v的祖先節點,也就是v的後繼節點中存在到達DFS序列中v的祖先的路徑,因此當DFS回溯到v節點時對於v的所有後繼節點u來說,都有low[u]<dfn[v]。

      如果v是一個割點,對所有v的後繼節點u進行DFS後,必然有low[u]>=dfn[v],這是因為,當遍歷v並將其鎖定後,到達v的祖先節點的路徑已經被封死,v的後繼節點必然不可能訪問到v的祖先節點,因此,必然有low[u]>=dfn[v]。

有了上面的分析,下面寫出求無向圖點割集的程式碼: