Tarjan of the strongly connected component of a Directed GraphAlgorithm[Digraph strongly connected component]
In directed graph G, if at least one path exists between two vertices, the two vertices are strongly connected ). If each vertex of directed graph G is strongly connected, G is a strongly connected graph. A very large strongly connected subgraph of A digraph of a non-strongly connected graph, known as strongrong connected components ).
In, the subgraph {1, 2, 3, 4} is a strongly connected component, because the vertex is reachable between 2, 2, 3, and 4. {5} and {6} are also two strongly connected components.
Based on the definition, we use bidirectional traversal to obtain the intersection to obtain the strongly connected component. The time complexity is O (n ^ 2 + M ). A better method is the kosaraju algorithm or the Tarjan algorithm. The time complexity of the two algorithms is O (n + M ). This document describes the Tarjan algorithm. [Tarjan algorithm]
The Tarjan algorithm is based on the image depth-first search algorithm. Each strongly connected component is a subtree in the search tree. When searching, add unprocessed nodes in the current search tree to a stack. When backtracking, you can determine whether the nodes on the stack are a strongly connected component.
Define dfn (u) as the node u search order number (timestamp), low (u) the sequence number of the earliest node in the stack that can be traced back to the U or U subtree. Can be derived from the definition,
Low (u) = min {dfn (u), low (v), (u, v) is the branch edge, U is the parent node dfn (V) of V, (u, v) is the backward edge pointing to the node in the stack (non-cross edge )}
When dfn (u) = low (u), all nodes in the Child tree with u as the root are a strongly connected component.
Algorithm pseudoCodeAs follows:
[C] View plaincopyprint?
- Tarjan <span style ="Color: #66cc66"> (</Span> U <span style ="Color: #66cc66">) </Span>
-
- <Span style ="Color: #66cc66">{</Span>
- dfn "color: #66cc66 " [ U " color: #66cc66 " ] = low " color: #66cc66 " [ U " color: #66cc66 " ] = ++ index " font-style: italic; color: #808080 " // set the sequence number and low initial value for node u
- stack. "color: #202020 " push " color: #66cc66 " ( U " color: #66cc66 " ) " font-style: italic; color: #808080 " // press node u into the stack
- "color: # b1b100 " for Each "color: #66cc66 " ( u, v " color: #66cc66 " ) in E " font-style: italic; color: #808080 " // enumerate each edge
- "color: # b1b100 " If "color: #66cc66 " ( V is not visted " color: #66cc66 " ) " font-style: italic; color: #808080 " // If node V has not been accessed
- Tarjan "color: #66cc66 " ( v " color: #66cc66 " ) " font-style: italic; color: #808080 " // continue searching
- low "color: #66cc66 " [ U " color: #66cc66 " ] = min " color: #66cc66 " ( low " color: #66cc66 " [ U " color: #66cc66 " ] , low " color: #66cc66 " [ v " color: #66cc66 " ] " color: #66cc66 " )
- "color: # b1b100 " else "color: # b1b100 " If "color: #66cc66 " ( V in S " color: #66cc66 " ) " font-style: italic; color: #808080 " // If node v is still in the stack
- low "color: #66cc66 " [ U " color: #66cc66 " ] = min " color: #66cc66 " ( low " color: #66cc66 " [ U " color: #66cc66 " ] , dfn " color: #66cc66 " [ v " color: #66cc66 " ] " color: #66cc66 " )
- <Span style = "Color: # b1b100" > If </Span> <span style = "Color: #66cc66" > (</Span> dfn <span style = "Color: #66cc66" > [</Span> U <span style = "Color: #66cc66" >] </Span> = low <span style = "Color: #66cc66" > [</Span> U <span style = "Color: #66cc66" >] </Span> <span style = "Color: #66cc66" >) </Span> <span style = "Font-style: italic; color: #808080" > // If the node u is the root of the strongly connected component </span>
-
- Repeat
- V = S. <span style ="Color: #202020"> Pop </span> <span style ="Font-style: italic; color: #808080">// Roll back the V to a vertex in the strongly connected component </span>
-
- Print v
- Until <span style ="Color: #66cc66"> (</Span> U = V <span style ="Color: #66cc66">) </Span>
-
- <Span style ="Color: #66cc66">}</Span>
Tarjan ( U ) { Dfn [ U ] = Low [ U ] = ++ Index// Set the sequence number and low initial values for node u Stack. Push ( U ) // Press node u into the stack For Each ( U, V ) In e // Enumerate each edge If ( V is not visted ) // If node V has not been accessed Tarjan( V ) // Continue searching Low [ U ] = Min ( Low [ U ] , Low [ V ] ) Else If ( V in S ) // If node v is still in the stack Low [ U ] = Min ( Low [ U ] , Dfn [ V ] ) If ( Dfn [ U ] = Low [ U] ) // If the node u is the root of the strongly connected component Repeatv = S. Pop // Roll back V to a vertex in the Strongly Connected Component Print vuntil ( U = V ) }
Next, we will demonstrate the algorithm flow.
From Node 1 to DFS, add the traversal nodes to the stack. When node u = 6 is found, dfn [6] = low [6] finds a strongly connected component. Stack back to u = V, {6} is a strongly connected component.
Return to node 5. dfn [5] = low [5] is found. After stack rollback, {5} is a strongly connected component.
Return to node 3, search for node 4, and add node 4 to the stack. It is found that node 4 has a backward edge to node 1, and node 1 is still in the stack, so low [4] = 1. Node 6 is out of the stack, () is the cross edge, 3 is returned, () is the branch edge, so low [3] = low [4] = 1.
Go back to node 1 and Access Node 2. The access edges (2, 4) and 4 are still in the stack, so low [2] = dfn [4] = 5. After 1 is returned, dfn [1] = low [1] is found, and all nodes in the stack are taken out to form a connected component {1, 3, 4, 2 }.
So far, the algorithm has ended. After this algorithm, all three strongly connected components {1, 3, 4, 2}, {5}, {6} in the graph are obtained }.
It can be found that each vertex is accessed once during the running of the Tarjan algorithm, and only once in and out of the stack, each side is accessed only once, therefore, the time complexity of this algorithm is O (n + M ).
There is also a powerful Algorithm for Finding the strongly connected component of a directed graph, namely the kosaraju algorithm. Kosaraju is based on the two DFS methods for Directed Graphs and their inverse graphs, and its time complexity is O (n + M ). Compared with the Trajan algorithm, the kosaraju algorithm may be slightly more intuitive. However, Tarjan only needs to perform DFS for the source image once, and does not need to create inverse graphs, which is more concise. In actual tests, the running efficiency of the Tarjan algorithm is about 30% higher than that of the kosaraju algorithm. In addition, the Tarjan algorithm is closely related to the Tarjan Algorithm for Finding undirected graph's dual-connected components (cut points and bridges. Learning the Tarjan algorithm also helps you to deeply understand the Tarjan Algorithm for dual-connected components. The two can be compared and combined.
The Tarjan algorithm used to calculate the strongly connected component of a directed graph is named after its inventor Robert Tarjan. Robert Tarjan also invented the Tarjan Algorithm for the dual-connected component and the offline Tarjan Algorithm for the recent public ancestor. He expressed his high respect for Tarjan.
Appendix: C ++ of the Tarjan AlgorithmProgram
[C] view plaincopyprint? 01. <PRE class = CPP name = "code"> # include <iostream> 02. # include <cstring> 03. # include <cstdio> 04. using namespace STD; 05. # define n 100 06. # define M 100 07. struct edge 08. {09. int V; 10. int next; 11 .}; 12. edge edge [m]; // a set of edges 13. 14.int node [N]; // vertex set 15.int instack [N]; // mark whether the node is 16.int in the stack [N]; 17.int belong [N]; // which strongly connected component each vertex belongs to? 18.int dfn [N]; // node u search sequence number (timestamp) 19.int low [N]; // The serial number (Time Stamp) vertex int n, m; // n: Number of vertices; M: Number of edges 21.int cnt_edge; // edge counter 22.int index; // No. (timestamp) 23.int top; 24.int bcnt; // Number of strongly connected components 25. 26. void add_edge (int u, int v) // The adjacent table is stored 27. {28. edge [cnt_edge]. next = node [u]; 29. edge [cnt_edge]. V = V; 30. node [u] = cnt_edge ++; 31 .} 32. void Tarjan (int u) 33. {34. int I, j; 35. int V; 36. dfn [u] = low [u] = ++ index; 37. instack [u] = true; 38. stack [++ top] = u; 39. for (I = node [u]; I! =-1; I = edge [I]. Next) 40. {41. V = edge [I]. V; 42. If (! Dfn [v]) // If vertex v is not accessed 43. {44. tarjan (V); 45. if (low [v] <low [u]) 46. low [u] = low [v]; 47 .} 48. else // If point V has been accessed 49. if (instack [v] & dfn [v] <low [u]) 50. low [u] = dfn [v]; 51 .} 52. if (dfn [u] = low [u]) 53. {54. bcnt ++; 55. do 56. {57. j = stack [top --]; 58. instack [J] = false; 59. belong [J] = bcnt; 60 .} 61. while (J! = U); 62 .} 63 .} 64. void solve () 65. {66. int I; 67. top = bcnt = Index = 0; 68. memset (dfn, 0, sizeof (dfn); 69. memset (low, 0, sizeof (low); 70. for (I = 1; I <= N; I ++) 71. if (! Dfn [I]) 72. tarjan (I); 73 .} 74.int main () 75. {76. freopen ("in.txt", "r", stdin); 77. int I, j, k; 78. cnt_edge = 0; 79. memset (node,-1, sizeof (node); 80. scanf ("% d", & N, & M); 81. for (I = 1; I <= m; I ++) 82. {83. scanf ("% d", & J, & K); 84. add_edge (j, k); 85 .} 86. solve (); 87. for (I = 1; I <= N; I ++) 88. printf ("% d", belong [I]); 89 .} 90. 91. </PRE> <br>