其實,tarjan演算法的基礎是dfs。我們準備兩個陣列low和dfn。low陣列是乙個標記陣列,記錄該點所在的強連通子圖所在搜尋子樹的根節點的dfn值(很繞嘴,往下看你就會明白),dfn陣列記錄搜尋到該點的時間,也就是第幾個搜尋這個點的。根據以下幾條規則,經過搜尋遍歷該圖(無需回溯)和對棧的操作,我們就可以得到該有向圖的強連通分量。
陣列的初始化:當首次搜尋到點p時,dfn與low陣列的值都為到該點的時間。
堆疊:每搜尋到乙個點,將它壓入棧頂。
當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』不在棧中,p的low值為兩點的low值中較小的乙個。
當點p有與點p』相連時,如果此時(時間為dfn[p]時)p』在棧中,p的low值為p的low值和p』的dfn值中較小的乙個。
每當搜尋到乙個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成乙個強連通分量。
由於每個頂點只訪問過一次,每條邊也只訪問過一次,我們就可以在o(n+m)的時間內求出有向圖的強連通分量。但是,這麼做的原因是什麼呢?
tarjan演算法的操作原理如下:
tarjan演算法基於定理:在任何深度優先搜尋中,同一強連通分量內的所有頂點均在同一棵深度優先搜尋樹中。也就是說,強連通分量一定是有向圖的某個深搜樹子樹。
可以證明,當乙個點既是強連通子圖ⅰ中的點,又是強連通子圖ⅱ中的點,則它是強連通子圖ⅰ∪ⅱ中的點。
這樣,我們用low值記錄該點所在強連通子圖對應的搜尋子樹的根節點的dfn值。注意,該子樹中的元素在棧中一定是相鄰的,且根節點在棧中一定位於所有子樹元素的最下方。
強連通分量是由若干個環組成的。所以,當有環形成時(也就是搜尋的下乙個點已在棧中),我們將這一條路徑的low值統一,即這條路徑上的點屬於同乙個強連通分量。
如果遍歷完整個搜尋樹後某個點的dfn值等於low值,則它是該搜尋子樹的根。這時,它以上(包括它自己)一直到棧頂的所有元素組成乙個強連通分量。
具體演算法演示下圖所示:
**實現: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include
#include
#define maxn 100000
struct
edgee[
maxn+1
];typedef
intarr
[maxn+1
];arr
head
,nxt
,stack
,dfn
,low;
bool
instack
[maxn+1
];int
tot,
index
,top
,cnum;
std::vector
<
int>
cset
[maxn+1
];//存強連通量
inline
void
link
(int
from
,intto)
; nxt[
tot]
=head
[from];
head
[from]=
tot;
}inline
intmin
(inta,
intb)
void
tarjan
(intu)
elseif(
instack[v
])}
if(dfn[u]
==low[u
])while(u
!=v&&top
>0)
; }
}int
main()
//for(int i=1;i<=ulimit;i++)
printf
("}");
} //printf("}");};
return0;
}they said "admonish your friends in private, praise them in public."
A 演算法 整理
a 演算法 目錄2.總結 注 本文引自 概念 a 探路搜尋,是指在有障礙物的時候,尋找到達目的地最短路徑的搜尋。先介紹一些前置知識助於自己理解a 啟發式搜尋 這是對每乙個搜尋位置進行評估,得到好的位置,再從這個位置進行搜尋直到目標。這樣子好處是 剪枝,效率更高。啟發式搜尋的關鍵是如何進行估價。估價函...
排序演算法整理
template void cinsertsort mysort function compare template void cselectsort mysort function compare swap datas i datas id void cshellsort mysort funct...
程式設計演算法整理
演算法一 快速排序演算法 快速排序是由東尼 霍爾所發展的一種排序演算法。在平均狀況下,排序 n 個專案要 n log n 次比較。在最壞狀況下則需要 n2 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 n log n 演算法更快,因為它的內部迴圈 inner loop 可以在大部分的架...