天天看點

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

目錄

一、無向圖割點、橋、雙連通分量

 Tarjan 算法求割點和橋(割邊)

“割點”代碼

邊雙和點雙連通分量

邊雙連通分量 和 點雙連通分量 的縮點

二、有向圖強連通分量

1.有向圖的弱連通與強連通

2.強連通分量

Kosaraju算法

Tarjan 算法(求強連通分量)

一、無向圖割點、橋、雙連通分量

  • 給定無向連通圖 G = (V, E)
  • 對于一個點 x,若從圖中删除 x 及所有與 x 相連的邊,圖不再連通,x 是 G 的割點
  • 對于一條邊 e,從圖中删去 e,圖不再連通, e 是 G 的割邊
  • 一個圖如果不存在割點,則它是一個點雙連通圖,一個圖的極大點雙連通子圖是它的點雙連通分量。
  • 一個圖如果不存在割邊,則它是一個邊雙連通圖,一個圖的極大邊雙連通子圖是它的邊雙連通分量。

先借用OI Wiki (傳送門)的圖解釋幾種邊:

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

 Tarjan 算法求割點和橋(割邊)

  • 時間戳 dfn:第幾個搜到這個點
  • 返祖邊:搜尋樹上一個點連向它另一條支鍊上的點的邊
  • (橫插邊:在搜尋樹上一個點連向它另一條支鍊上的點的邊——在無向圖中不存在【因為下一條支鍊在dfs序中會直接接在目前這條支鍊後面成為“子樹”】
  • 追溯值 low:目前點及其子樹通過一條返祖邊能連到的最小 dfn 值
  • 如果 <u, v> 是搜尋樹的邊:low[u] = min(low[u], low[v])
  • 如果 <u, v> 是返祖邊:low[u] = min(low[u], dfn(v))

下面來看一個連通圖,尋找割點和割邊(橋)所滿足的規律。右圖為左圖的一個dfs搜尋樹,水藍色标記每個點的dfn(時間戳),梅紅色标記每個點的 low 值。

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

low 值宜從葉節點開始标記,因為其值作為子節點可以向上更新父節點的 low 值,比如序号為4的點有一條連向1号節點的返祖邊,其 low 值為1,7号結點 low 值等于其 dfn = 9,10号結點 low 值也為8,而對于8号結點,它的子樹中4号結點 low 值為1,根據 “ 如果 <u, v> 是搜尋樹的邊:low[u] = min(low[u], low[v]) ” ,其 low 值為1 ,再依次向上更新。

例如:10号點為割點,若将其去掉,其下的7号結點無法與上面的連通。

規律:【割點有兩類】:

  1. 子樹裡不存在跨越它連向它上方的點的邊
  2. 有多個兒子的根

(u, v)割邊(u 為父親,v 為兒子):以 v 為根的子樹中不存在連向 u 以及 u 上方的邊。

用low和dfn的關系表示即
  • u點是割點, v 是 u 搜尋樹上的一個兒子:① dfn[u] <= low[v] —— v的子樹中沒有返祖邊能跨越 u 點;② 有多個兒子的根節點
  • 邊是橋,搜尋樹上 v 是 u 的一個兒子:dfn[u] < low[v] —— v 的子樹中沒有返祖邊能跨越<u,v> 這條邊
注意割點的式子有等号,判割邊的沒有等号(如果有一條返祖邊将 v 與 u 相連,則dfn[u] = low[v] ,這時原本v和u相連的邊删掉也能連通,故u-v不是割邊) 

“割點”代碼

注意第32行為 dfn[y],與第25行的 low[y] 不一樣。在求“割邊”裡寫成 low[y] 雖然也不會錯,但在求割點裡就是錯的,可能有些題目資料不夠強這裡寫錯了也能過,但一旦錯了就很難找到,是以極度建議割點割邊代碼此處按照定義寫成一緻,能大大減少出錯率。

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

關于為什麼寫low[y]為錯的說明:

如下圖,因為搜尋的順序不确定(取決于建圖時的順序)若3号點的low值通過一條返祖邊更新為1後,再來更新5号結點時,若是 low[x] = min(low[x],low[y]),low[5]=low[3]=1,然後4号點就會繼承5号點的 low 值也為1,這樣dfn[3]>=low[4],就會誤判點3不是割點,而事實上3号點是割點。這裡相當于是将1--3這條返祖邊與3--5這條返祖邊連起來當成了1--5的返祖邊,而我們的low值定義是目前點及其子樹通過一條返祖邊能連到的 最小dfn 值。5到3,3再到1,而3恰是我們的割點,而求割邊的時候就不會出現這種情況,跨越了一條邊就是跨越了一條邊,不會存在要兩條邊連在一起才跨越一條邊。

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

邊雙和點雙連通分量

  • 把橋删了每個連通塊都是一個邊雙連通分量——标記處橋之後dfs一遍即可
  • 點雙連通分量要複雜一些——一個割點可能屬于多個雙連通分量
連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量
連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

 dfs時(這裡假設在8号結點先搜向9的那條支鍊)……9入棧,6入棧,10入棧,再向上傳回(系統dfs遞歸調用的傳回,系統棧的10,6,9彈出,自己維護的棧沒有彈出)當傳回到結點8時,dfn[8] <= low[y],判斷8為割點,此時彈出自己維護的棧裡8以上的所有結點(10,6,9)與8組成一個點雙連通分量;8再到7号結點,發現7号結點沒有兒子結點了,再傳回,又成立dfn[8]<=low[7],8為割點,于是彈出7号點與8組成第二個點雙連通分量;8再到4,發現low[4]=1,low[4] < dfn[8],8不是其中的割點……到最後回到根節點1,因為所有的結點的low值總不會比根節點的dfn還要小,即隻有一個子節點的根節點總是割點,是以靠1号根節點将剩餘的所有點彈出,組成最後一個點雙連通分量。(無所謂,根節點會出手)

邊雙連通分量 和 點雙連通分量 的縮點

  • 每個邊雙連通分量縮成一個點,再用原來的橋把它們連起來
  • 點雙連通分量因為一個割點可能包含在多個點雙連通分量裡面,是以我們将每個割點保留割點與其所在的點雙連通分量連邊即可。

如上圖的點雙連通分量可改為:

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

二、有向圖強連通分量

1.有向圖的弱連通與強連通

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

2.強連通分量

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

 如上圖的黃色點構成一個強連通分量。

Kosaraju算法

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

對左圖,從1開始搜:1進棧,5進棧,8進棧,4進棧,3進棧,3不能往下搜了,3出棧,回到4,4也沒有向下搜的點,4出棧,回到8,6進棧,6出棧,8出棧,5出棧,1出棧;

然後再找圖中一個沒有通路過的點繼續上述操作,從2開始,2入棧,2出棧;

再從7開始,7入棧,9入棧,9出棧,7出棧。

得到出棧順序:3,4,6,8,5,1,2,9,7

再以這個出棧時間的逆序對反圖(即原來A->B變為B->A)進行dfs:從7開始,7無法到達其它點,7獨自為一個強連通分量;再看9,因為9原本能去到的7已經被删了,9也單獨是一個強連通分量;2号點為一個強連通分量;1号點為一個強連通分量(原本可以通向的2号點已經成為一個單獨的強連通分量了);又5->3->4->8,3->6,是以5,3,4,6,8為一個強連通分量

原理:在一個 dfs 搜尋樹裡面,越先出棧說明越多的點可以到達這個點,即在它後面的點都能到達它,如【3,4,6,8,5,1】3後面的點都能到達3,4後面的點都能到達4,依此類推。若順序為A, B, C, 則實際圖中關系為 A<--B<--C,那麼倒叙,反圖能到(C-->B)也即原圖有反向邊能到(C<--B)【意會~意會~】 

Tarjan 算法(求強連通分量)

連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量
連通性1(Tarjan 理論版)一、無向圖割點、橋、雙連通分量二、有向圖強連通分量

繼續閱讀