1. 程式人生 > 實用技巧 >割點/割邊

割點/割邊

割點/割邊

1.定義:

對於一個無向圖,
如果刪除一個點,可以讓一個圖的連通分支數增加。那麼這個點就是割點
同樣的,對於一條邊,刪掉之後可以讓一個圖的連通分支數增加,那麼這條邊就是割邊

2.關鍵的性質:

對於一條在連通圖G中的割邊e,一定存在這樣的性質:

e不在G中的任意一個圈上。

如果我們對一個連通的無向圖進行dfs,那麼我們就會得到一顆dfs樹
這是有了這樣的兩個定理:

第一, 根節點u是割點,當且僅當,u有兩個及兩個以上的子樹。

就是它把多個子樹分隔開。注意這裡說的是子樹,子樹是互不連通的。

第二,非根節點u是割點,當且僅當,後代v都不可以通過回退邊回到u的祖先w

如果v可以通過回退邊回到w會發生什麼?
顯然這樣會形成一個圈。如下圖

顯然,圖中的u不是割點。因為v可以返回到u的祖先 w。
但是對於w而言呢?後代u和v都不可以返回到w的祖先s,所以w是割點。

討論完了割點,我們來看看割邊。

 圈上的邊一定不是割邊

這是很顯然的。如果u到v之間有圈,那麼一定至少會有兩條(u,v),任意刪除一條邊都不會改變連通性。

3.割點演算法的描述:

在dfs中,每一個點有兩個資料:
dfn記錄訪問的時間點,也就是時間戳
low記錄的是 可以回溯到的最早祖先的時間戳
之前我們討論了,對於每一個節點的而言,我們需要分兩個情況討論。根與非根。
對於根來說我們只需要記錄後代子樹的個數就行了。
那麼如何處理非根的情況呢。
只需要u的後代結點v滿足:

low[v] >= dfn[u].

也就是說,v可以回溯到的最早的節點low[v]
仍然在u之下。
當然這裡有兩種情況,後向邊和橫叉邊。
後向邊:
這就像是,一根繩子上,一邊是一個圈,另一邊是另一個圈,割掉繩子上的任意一個點,就會使兩個物體分開。那麼很顯然繩子上的每一個都是割點。
橫叉邊:
如果是橫叉邊我們發現這一定會回溯到根節點,這是一定會比dfn[u]小的,也就是說這是不可能的。

現在我們已經有了求割點的演算法了:

dfs(int u){
   for:each v of u{
      if(v not visted){
           dfs(v)
           low[u] = min(low[u],low[v]);
           if(low[v] >= dfn[u]){
               child++;
               if(u is not root)
                  u is cut;
               else if(child > 1)
                  u is cut;
           }
      }
      else low[u] = min(low[u],dfn[v]);
   }
}

4.割邊演算法的描述:

在已經得到了割點演算法的同時我們來看看割邊演算法。在上述的討論中我們發現,割邊演算法和割點演算法是類似的。
橫叉邊一定會形成環,也就是一定會回溯到根。
後向邊與割點是相同,但是不需要特判一個根。
正常的判斷,也只需要將 low[v] >= dfn[u],改為low[v]>dfn[u]這就得到了我們的割邊(u,v)。這是因為我們得到的(u,v)一定不是圈上的邊,當取等號時,可以發現此時的(u,v)仍然在圈上。但是此時u確是割點。