成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

20行代碼實現,使用Tarjan算法求解強連通分量

開發 前端 算法
今天介紹的算法名叫Tarjan,同樣是一個很奇怪的名字,奇怪就對了,這也是以人名命名的。和Kosaraju算法比起來,它除了名字更好記之外,另外一個優點是它只需要一次遞歸,雖然算法的復雜度是一樣的,但是常數要小一些。它的知名度也更高,在競賽當中經常出現。

今天介紹的算法名叫Tarjan,同樣是一個很奇怪的名字,奇怪就對了,這也是以人名命名的。和Kosaraju算法比起來,它除了名字更好記之外,另外一個優點是它只需要一次遞歸,雖然算法的復雜度是一樣的,但是常數要小一些。它的知名度也更高,在競賽當中經常出現。

先給大家提個醒,相比于Kosaraju算法,Tarjan算法更難理解一些。所以如果你看完本文沒有搞明白的話,建議可以閱讀一下上一篇文章。這兩個算法的效果和復雜度都是一樣的,其實學會一個就可以,沒必要死磕。

算法框架

我們來思考一個問題,對于強連通分量分解的算法來說,它的核心原理是什么?

如果你看過我們之前的文章,那么這個問題對你來說應該不難回答。既然是強連通分量,意味著分量當中每個點都可以互相連通。所以我們很容易可以想到,我們可以從一個點出發,找到一個回路讓它再回到起點。這樣途中經過的點就都是強連通分量的一部分。

但是這樣會有一個問題,就是需要保證強連通分量當中的每個點都被遍歷到,不能有遺漏。針對這個問題我們也可以想到解法,比如可以用搜索算法去搜索它所有能夠達到的點和所有的路徑。但是這樣一來,我們又會遇到另外一個問題。這個問題就是強連通分量之間的連通問題。

我們來看個例子:

 

20行代碼實現,使用Tarjan算法求解強連通分量

在上面這張圖當中如果我們從點1出發,我們可以達到圖中的每一個點。但是我們會發現1,2,3是一個強連通分量,4,5,6是另外一個。當我們尋找1所在的強連通分量的時候,很有可能會把4,5,6這三個點也帶進來。但問題是它們是自成分量的,并不應該算在1的強連通分量當中。

我們整理一下上面的分析和思路可以發現強連通分量分解這個算法的核心其實就是解決這兩個問題,就是完備性問題。完備意味著不能遺漏也不能冗余和錯誤,我們想明白核心問題所在之后就很容易搭建起思維框架,接下來我們再來看算法的描述會容易理解得多。

算法細節

Tarjan算法的第一個機制是時間戳,也就是在遍歷的時候對每一個遍歷到的點打上一個值。這個值表示這是第幾個遍歷的元素。

這個應該很好理解,我們只需要維護一個全局的變量,在遍歷的時候去讓它自增就可以了。我們來寫下Python代碼給大家演示一下:

  1. stamp = 0 
  2. stamp_dict = {}def dfs(u): 
  3.     stamp_dict[u] = stamp    stamp += 1 
  4.     for v in Graph[u]: 
  5.         dfs(v) 

通過時間戳我們可以知道每個點被訪問的順序,這個順序是正向順序。舉個例子,比如說假設u和v兩個點,u的時間戳比v小。那么它們之間的關系只有兩種可能,第一種是u能夠連通到v,說明從u到v的鏈路可以走通。第二種是u不能連通到v,這種情況不論反向的從v到u能否連通都不具有討論意義,因為它們一定不能互相連通。

所以我們想要找到連通的通路還需要找到反向的路徑,在Kosaraju算法當中我們是通過反向圖來實現的。在Tarjan當中則采取了另外一種方法。因為我們已經知道各個點的時間戳了,我們完全可以通過時間戳來尋找反向的路徑。什么意思呢?其實很簡單,當我們在遍歷u的時候如果遇到了一個比u時間戳更小的v,那么說明就存在一條反向的路徑從u通向v。如果v這時候還沒有出棧,意味著v是u的上游的話,那么也就說明存在一條路徑從v通向u。這樣就說明了u和v可以互相連通。

既然找到了一對互相連通的u和v,那么我們需要把它們記錄下來。但問題是我們怎么知道記錄到什么時候為止呢?這個邊界在哪里?Tarjan算法設計了另外一個巧妙的機制解決了這個問題。

這個機制就是low機制,low[u]表示u這個點能夠連通到的所有的點的時間戳的最小值。時間戳越小說明在搜索樹當中的位置越高,也可以理解成u能夠連通到的處在搜索樹中最高的點。那么很明顯了,這個點就是u這個點所在強連通分量所在搜索樹某一棵子樹的樹根。

這里可能有一點點繞,我們再來看張圖:

 

20行代碼實現,使用Tarjan算法求解強連通分量

圖中節點所在的序號就是遞歸遍歷的時間戳,我們可以發現對于圖上的每個點來說它們的low值都是1。很明顯1這個點在搜索樹當中是2,3,4這三個點的祖先。也就是說這一個強連通分量的遍歷是從1這個點開始的。當1這個點出棧的時候,意味著以1位樹根的子樹已經遍歷完了,所有可能存在的強連通分量也都已經找完了。

這就帶來了另外一個問題,我們假設當前點是u,我們如何知道u這個點是否是圖中1這樣的樹根呢?有沒有什么辦法可以標記出來呢?

當然是有的,這樣的點有一個特性就是它們的時間戳等于它們的low。所以我們可以用一個數組維護找到的強連通分量,當這些強連通分量能夠遍歷到的樹根出棧的時候,把數組清空。

我們把上面的邏輯整理一下就可以寫出代碼來了:

  1. scc = [] 
  2. stack = [] 
  3. def tarjan(u):    dfn[u], low[u] = stamp, stamp    stamp += 1 
  4.  stack.append(u) 
  5.         for v in Graph[u]: 
  6.         if not dfn[v]: 
  7.             tarjan(v)            low[u] = min(low[u], low[v])        elif v in stack: 
  8.          low[u] = min(low[u], dfn[v])       if dfn[u] == low[u]: 
  9.         cur = []        # 棧中u之后的元素是一個完整的強連通分量        while True
  10.             cur.append(stack[-1]) 
  11.             stack.pop() 
  12.             if cur[-1] == u: 
  13.                 break 
  14.         scc.append(cur) 

最后,我們來看一下之前講過的經典例子:

 

20行代碼實現,使用Tarjan算法求解強連通分量

首先我們從1點開始,一直深搜到6結束,當遍歷到6的時候,DFN[6]=4,low[6]=4,當6出棧時滿足條件,6獨立稱為一個強連通分量。

 

20行代碼實現,使用Tarjan算法求解強連通分量

同理,當5退出的時候也同樣滿足條件,我們得到了第二個強連通分量。

 

20行代碼實現,使用Tarjan算法求解強連通分量

接著我們回溯到節點3,節點3還可以遍歷到節點4,4又可以連向1。由于1點已經在棧中,所以不會繼續遞歸1點,只會更新low[4] = 1,同樣當4退出的時候又會更新3,使得low[3] = 1。

 

20行代碼實現,使用Tarjan算法求解強連通分量

最后我們返回節點1,通過節點1遍歷到節點2。2能連通的4點已經在棧中,并且DFN[4] > DFN[2],所以并不會更新2點。再次回到1點之后,1點沒有其他點可以連通,退出。退出的時候發現low[1] = DFN[1],此時棧中剩下的4個元素全部都是強連通分量。

 

20行代碼實現,使用Tarjan算法求解強連通分量

到這里,整個算法流程的介紹就算是結束了,希望大家都可以enjoy今天的內容。

 

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2017-11-14 14:54:00

數據結構DFNS深度優先

2021-04-28 07:59:21

深度優先搜索

2022-03-26 22:28:06

加密通信Python

2022-04-15 08:07:21

ReactDiff算法

2018-02-08 16:45:22

前端JS粘貼板

2024-11-08 17:22:22

2022-03-21 10:13:09

sftp 服務器參數配置

2015-09-21 09:36:54

20 億代碼谷歌

2015-09-18 11:47:45

代碼Google管理

2019-07-24 16:00:37

Python代碼高清圖片

2015-07-15 10:19:16

Java代碼使用緩存

2022-05-09 13:59:41

Python提取PPTword文檔

2020-10-30 11:19:17

信息化云計算大數據

2020-06-18 15:53:06

Python代碼摳圖

2023-11-06 11:33:15

C++數獨

2020-12-17 08:06:33

CSS 日歷界面

2018-01-23 09:17:22

Python人臉識別

2020-05-20 12:50:32

代碼線性方程開發

2022-04-09 09:11:33

Python

2014-10-13 15:17:59

代碼托管
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美精品久久 | 欧美一级在线观看 | 国产一区91精品张津瑜 | 亚洲综合成人网 | 精品视频一区二区三区在线观看 | 天堂免费看片 | 超碰最新在线 | 日韩成人免费 | 精品久久免费 | 狠狠爱网址| 国产精品美女视频 | 久久久久久免费精品一区二区三区 | 欧美日韩在线一区二区 | www.色综合| 欧美色综合天天久久综合精品 | 久久一区二区三区免费 | 国产精品久久久久久吹潮 | 精品久久中文 | 久久aⅴ乱码一区二区三区 91综合网 | 国产精品永久免费观看 | 99精品国产一区二区青青牛奶 | 永久免费av | 97久久久 | 久久久高清 | 最近中文字幕免费 | a级在线 | 日韩视频免费看 | 免费成人在线网站 | 免费视频久久 | 91精品国产自产精品男人的天堂 | 婷婷国产一区二区三区 | 波多野结衣一区二区三区在线观看 | 欧美 中文字幕 | 国产精品精品 | 国产一区二区三区四区在线观看 | 免费午夜视频在线观看 | 国产中文一区二区三区 | www成人免费视频 | www.性色 | 亚洲一区中文字幕 | 亚洲精品久久国产高清情趣图文 |