Tajin算法由Robert Tarjan提出,他可以在线性时间内帮我们找到有向图中的所有强连通分量。
其实,tarjan算法的基础是DFS。我们准备两个数组Low和Dfn。Low数组是一个标记数组,记录该点所在的强连通子图所在搜索子树的根节点的Dfn值(很绕嘴,往下看你就会明白),Dfn数组记录搜索到该点的时间,也就是第几个搜索这个点的。根据以下几条规则,经过搜索遍历该图(无需回溯)和对栈的操作,我们就可以得到该有向图的强连通分量。
由于每个顶点只访问过一次,每条边也只访问过一次,我们就可以在O(n+m)的时间内求出有向图的强连通分量。但是,这么做的原因是什么呢?
Tarjan算法的操作原理如下:
具体算法演示下图所示:
代码实现:
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
Edge
{
int
from
;
int
to
;
}
e
[
MAXN
+
1
]
;
typedef
int
arr
[
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
,
int
to
)
{
//连边
e
[
++
tot
]
=
(
Edge
)
{
from
,
to
}
;
nxt
[
tot
]
=
head
[
from
]
;
head
[
from
]
=
tot
;
}
inline
int
min
(
int
a
,
int
b
)
{
if
(
a
<
b
)
return
a
;
return
b
;
}
void
tarjan
(
int
u
)
{
//模拟图中过程
int
v
;
DFN
[
u
]
=
index
++
;
LOW
[
u
]
=
DFN
[
u
]
;
stack
[
++
top
]
=
u
;
//模拟栈
instack
[
u
]
=
true
;
for
(
int
i
=
head
[
u
]
;
i
!=
0
;
i
=
nxt
[
i
]
)
{
v
=
e
[
i
]
.
to
;
if
(
DFN
[
v
]
==
0
)
{
tarjan
(
v
)
;
LOW
[
u
]
=
min
(
LOW
[
u
]
,
DFN
[
v
]
)
;
}
else
if
(
instack
[
v
]
)
{
LOW
[
u
]
=
min
(
LOW
[
u
]
,
DFN
[
v
]
)
;
}
}
if
(
DFN
[
u
]
==
LOW
[
u
]
)
{
//找到强连通量,退栈
cnum
++
;
do
{
v
=
stack
[
top
--
]
;
instack
[
v
]
=
false
;
cset
[
cnum
]
.
push_back
(
v
)
;
//printf("%d,",v);
}
while
(
u
!=
v
&&
top
>
0
)
;
}
}
int
main
(
)
{
int
x
=
1
,
y
=
1
,
ulimit
=
0
;
scanf
(
"%d%d"
,
&x
,
&y
)
;
while
(
x
>
0
&&
y
>
0
)
{
link
(
x
,
y
)
;
scanf
(
"%d%d"
,
&x
,
&y
)
;
ulimit
=
x
>
ulimit
?
x
:
ulimit
;
}
//for(int i=1;i<=ulimit;i++) { printf("{");
tarjan
(
1
)
;
for
(
int
i
=
1
;
i
<=
cnum
;
i
++
)
{
printf
(
"{"
)
;
while
(
!
cset
[
i
]
.
empty
(
)
)
{
printf
(
"%d,"
,
cset
[
i
]
.
back
(
)
)
;
cset
[
i
]
.
pop_back
(
)
;
}
printf
(
"}"
)
;
}
//printf("}");};
return
0
;
}
|
They Said "Admonish your friends in private, praise them in public."
原文地址:http://ozem.pw/archives/585