尋找圖的強連通份量:tarjan算法簡單理解

一、簡介
tarjan是一種使用深度優先遍歷(DFS)來尋找有向圖強連通份量的一種算法。算法

二、知識準備
棧、有向圖、強連通份量、DFS。數組

三、快速理解tarjan算法的運行機制
提到DFS,能想到的是經過棧來儲存沿途的點,能夠找到全部的環。環自己就是聯通的,因此環對於強連通份量來講環已經很接近最終答案了。要把找環變成找強連通管份量還要考慮:
a.在環外是否是有其餘環在這個強連通份量內(極大性)spa

(會被認爲是2個環).net

b.一些不能構成環的點沒法被考慮到,而他們自己就是強連通份量code

(2不被認爲是一個強連通份量)blog

 

因此Tarjan算法除了棧還引入了2個數組,分別是:
DFN[N]//節點的時間戳,用來標記節點訪問的前後順序(以及是否被訪問過)
Low[N]//當前「環」裏最早被訪問到的節點,至關於當前這個強連通份量裏的根class


Tarjan的流程是:
DFS,每遇到一個未被訪問過的節點就初始化DFN[i]=Low[i]=index++;
若是找到了環,就在遍歷中用Low數組向上傳遞根的時間戳,直到找到一個點他的時間戳和根的時間戳一致,即DFN[i]=Low[i],這就說明這個點就是根。此時,棧內的全部在根後面的點(包括根)就組成一個強連通份量。遍歷

四、僞代碼im

index=0;
tarjan(u)
{
    DFN[u]=low[u]=index++;
    u入棧;
    for(遍歷每條邊(u,v))
    {
        if(v未被訪問)
        {
            tarjan(v);//DFS
            low[u]=min(low(u),DFN(v));//將下方的時間戳向上傳遞
        }
        else if(v在棧內)
        {
            low[u]=min(low[u],DFN(v));//找到環,比較當前保存的根的時間戳和v的時間戳,取較早的那個做爲根
        }
        if(DFN(u)==low[u])
        {
            //回到了根節點,此時棧內從u日後的節點都是該強連通份量的節點
            //找到了強連通份量,逐個退棧,輸出
        }
    }
}


五、進一步說明
a.對於問題a,爲何能找到強連通份量內其餘的環?
DFS的問題在於,找到了環當即處理而不考慮其餘環;Tarjan算法把輸出交給根節點處理,在到根節點以前,算法已經遍歷的根節點下的全部節點,天然也把全部環放入了棧。
b.對於問題b,爲何考慮到了不能構成環的那些節點?
對於這些節點,DFN(u)==low[u],至關於他們自己就是強連通份量的根節點。時間戳

六、延伸閱讀若是您仍然有疑問,能夠參考https://blog.csdn.net/qq_34374664/article/details/77488976

相關文章
相關標籤/搜索