強連通分量、割點、橋

來源:互聯網
上載者:User

標籤:

一、強連通分量

    在有向圖G中,如果任意兩個不同的頂點相互可達,則該有向圖為強連通的;一個有向圖G的極大連通子圖稱為G的強連通分支;將有向圖G的每一條邊反向形成的圖稱為G的轉置 Gt.

1.1 有向圖的一些定理
  1. 有向非循環圖中唯一出度為0的點,一定可以由任何點出發到達 
        圖中節點的數目為有限多個,而且無環,因此從任何點出發往前走,一定終止於出度為0的點,否則走N+1步(N為圖中節點的數目),則必然有一個點被走了兩次,形成了環,與無環矛盾!

  2. 有向非循環圖中所有入度不為0的點,一定可以由某個入度為0的點出發可達 
        由於無環,所以從任何入度不為0的點往回走,必然終止於一個入度為0的點。

1.2 強連通分量的求解

    一個有向圖G可以存在多個極大連通子圖,即多個強連通分支。求一個有向圖的強連通分支的方法主要有:Korasaju演算法和Tarjan演算法。

1.2.1 Korasaju演算法 
1. 深度優先遍曆圖G,演算法每個節點u的結束時間f[u],起點如何選擇無所謂; 
2. 深度優先遍曆G的轉置圖Gt,選擇遍曆的起點的時候,按照節點的結束時間從大到小進行。遍曆的過程中,一邊遍曆,一邊給節點做分類標記,每找到一個新起點,分類標記就加1; 
3. 第2步中產生的標記值相同的節點構成深度優先森林中的一棵樹,也即一個強連通分量

1.2.2 Tarjan演算法 
1. 做一遍DFS,用dfn[i]表示編號為i的節點在DFS過程中的訪問序號(也可以叫做開始時間)。DFS過程中會形成一棵搜尋樹,在搜尋樹上越先遍曆到的節點,dfn的值就越小。dfn值越小的節點,就稱為越“早”。 
2. low[i]表示從i節點出發DFS過程中i下方節點(開始時間大於dfn[i],且由i可達的節點)所能到達的最早的節點的開始時間。初始時 low[i] = dfn[i]. 
3. DFS過程中,碰到哪個節點,就將哪個節點入棧。棧中節點只有在其所屬的強連通分量已經全部求出時,才會出棧。 
4. 如果發現某節點u有邊串連到棧裡的節點v,則更新u的low值為 min(low[u], dfn[v])。若low[u]被更新為dfn[v],則表明目前發現u可達的最早的節點是v。 
    (1)對於u的子節點v,從v出發進行的DFS結束回到u時,使得low[u] = min(low[u], low[v])。因為u可達v,所以v可達的最早的節點,也是u可達的。 
    (2)如果一個節點u,從其出發進行的DFS已經全部完成並回到u,而且此時 low[u] == dfn[u],說明u可達的所有節點,都不能到達任何比u早的節點——那麼,該節點u就是一個強連通分量在DFS搜尋樹中的根。此時,顯然棧中u上方的節點,都是不能到達比u早的節點的。將棧中節點彈出,一直彈到u(包括u),彈出的節點就構成了一個強連通分量。

void Tarjan(int u){    dfn[u] = low[u] = ++index;    stack.push(u);    for each(u,v) in E{        if (v is not visited){            Tarjan(v);            low[u] = min(low[u], low[v]);        }else if (v in stack){            low[u] = min(low[u], dfn[v]);        }    }    if (dfn[u] == low[u]){ //u是一個強連通分量的根        repeat            v = stack.pop            print v        until (u == v)    }//退棧,把整個強連通分量都彈出來}

 

二、割點和橋

    無向連通圖中,如果刪除某點後,圖變成不連通,則稱該點為割點 
    無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋

求割點和橋的Tarjan演算法

    思路和求有向圖的強連通分量類似,在深度優先遍曆整個圖過程中形成一棵搜尋樹。定義dfn[u]為節點u第一次被訪問到的時間(序號),low[u]為u或者u的子樹中能夠通過非父子邊(父子邊就是搜尋樹上的邊)追溯到的最早的節點的DFS開始時間。 
    一個頂點u是割點,若且唯若滿足(1)或(2) 
(1)u為樹根,且u有多於一個子樹 
(2)u不為樹根,且存在(u,v)為樹枝邊(或稱父子邊,即u為v在搜尋樹中的父親),使得 dfn(u) <= low(u)

    一條邊(u,v)是橋,若且唯若 
(u,v)為樹枝邊,且滿足dfn(u) < low(v)。注意,(u,v)不能有重邊。

Tarjan演算法在DFS過程中判斷割點或橋

void Tarjan(u){   dfn[u] = low[u] = ++index;   for each(u,v) in E{        if (v is not visited){            Tarjan(v)            low[u] = min(low[u], low[v])            if(d[u] < low[v])                (u,v)為橋        }else if (v 不是 u的父節點){            low[u] = min(low[u], dfn[v]);        }    }    if (u 為根)        u是割點 <=> u 有至少兩個子節點    else        u是割點 <=> u 有一個子節點v,滿足 dfn[u] <= low[v]}

 


Tarjan演算法之後判斷割點或橋 
    可以先用Tarjan進行dfs算出所有點的low和dfn值,並記錄dfs過程中每個點的父節點,然後再把所有點看一遍,看起low和dfn,以找出割點和橋。 
    找橋的時候,需要注意有無重邊,若有重邊,則不是橋。

三、無向連通圖點雙連通分支

    無向連通圖的點雙連通分支是指不包含割點的極大連通子圖。 
1. 建立一個棧,儲存當前雙連通分支,搜尋圖時,每找到一條樹枝邊或反向邊(連到樹中祖先的邊),就把這條邊加入棧中。 
2. 如果遇到某樹枝邊(u,v)滿足dfn[u] <= low[v],說明u是一個割點,此時把邊從棧頂一個個取出,直到遇到了邊(u,v),取出的這些邊與其關聯的點,組成一個點雙連通分支。 
3. 割點可以屬於多個點雙連通分支,其餘點和每條邊只能屬於一個點雙連通分支

四、無向連通圖邊連通分支

    無向連通圖的邊雙連通分支是指不包含橋的極大連通子圖。 
求無線連通圖的邊連通分支,只需要在求出所有的橋以後,把橋邊刪除,原圖就變成了多個連通塊,則每個連通塊就是一個邊連通分支。 
    橋不屬於任何一個邊連通分支,其餘的邊和每個頂點都屬於且只屬於一個邊連通分支。

強連通分量、割點、橋

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.