tarjan演算法入門(一)——割點割邊(未完成割點部分)
一.概述.
tarjan演算法是Robert tarjan發明的一種基於深度優先遍歷的演算法,這種演算法可以求無向圖的割點(割頂)割邊(橋),進一步可以用於求無向圖的雙連通分量;在有向圖方面可以求出強連通分量等.
二.割點與割邊.
割點與割邊是圖論中重要的概念.
割點的定義:在一張無向圖中,去掉一個點,可以將這個點所在的聯通塊分成兩個或多個聯通塊,則稱這個點是這張無向圖的割點.
割邊的定義:在一張無向圖中,去掉一條邊,可以將這條邊所在的聯通塊分成兩個或多個聯通塊,則稱這個點是這張無向圖的割邊.
三.tarjan演算法.
關於tarjan演算法的定義,本人也不是很清楚,可能就是一類用到了生成樹或者dfn與low值的深度優先遍歷演算法吧.
運用tarjan演算法求割點與割邊首先要了解dfn與low值.
dfn值:dfn值其實就是時間戳,深度優先遍歷時一個點i的dfn值就是一個點被遍歷到的順序(即被遍歷到之前有幾個節點被遍歷過).
low值:
我們dfs遍歷出來的是一棵生成樹,在這棵生成樹上的邊我們稱作樹邊,其它邊我們稱作非樹邊.
那麼一個點的low值即為一個點通過由非樹邊組成的路徑能夠達到的dfn值最小的點的dfn值.
定理1:對於任意一條邊,這條邊連線的兩點在生成樹上一定是祖先與後代的關係.
證明如下:
若一條邊連線的兩點在生成樹上不是祖先與後代,那麼dfs是應該會從先dfs到的那個點dfs到另一個點,與假設相矛盾.
證畢.
那麼我們現在就可以搬出定理2了.
定理2:若一條邊是割邊,則這條邊只會出現在生成樹上,且這條邊連線的父親的dfn值要大於兒子的low值.
證明如下:
若這條邊是非樹邊,則去掉這條邊之後,生成樹一節連通,與割邊的定義相矛盾.
若這條邊的兒子的low值大於或等於了父親的dfn值,根據low值的定義,去掉這條邊後,這個兒子能夠連通到的dfn值最小的點要小於它的父親.
根據定理1,我們可以知道一條邊連線的點的關係一定是祖先與後代,所以這個兒子可以連通到祖先,聯通塊沒有被破壞,與割邊的定義相矛盾.
證畢.
那麼現在我們要做的就是在一個dfs內求出dfn值和low值,就可以得到割邊了.
那麼演算法流程如下:
1.進行dfs,先確定這個點的dfn值.
2.遍歷這個點的所有兒子.
3.每遍歷一個兒子後,利用定理2判定這個兒子到它的邊是否為割邊,並打上標記.
4.若一個兒子沒有被遍歷過,則將這個點當前的low值與它兒子的low值取min.
5.若這個點被遍歷過,則將這個點當前的low值與它兒子的dfn值取min.
那麼求割邊的模板如下:
void dfs(int k,int fa){
dfn[k]=low[k]=++tt;
for (int i=lin[k];i;i=e[i].next){
int y=e[i].y;
if (!dfn[y]) {
dfs(y,k);
low[k]=min(low[y],low[k]);
if (low[y]>dfn[k]) e[i].br=e[i^1].br=1;
}else if (y^fa){
low[k]=min(dfn[y],low[k]);
}
}
}