Tarjan algorithm [reading notes]

Application: linear time obtaining the undirected graph cut point of the bridge, two connected components. The strongly connected component, and a necessary point must pass through the edges.

Mainly seeking two things, dfn and low

Timestamp dfn: it is dfs sequence, i.e. each node in the chronological order traversal procedure dfs first accessed.

Retrospective values Low : $ Low [X] as defined $ $ min (dfn [subtree (x ) of the node], DFN [longer sides by searching a tree to reach the node subtree (x)] A) $, where $ subtree (x) $ is the search tree to $ X $ is the root node.

In fact, this value represents the node is the first to be accessed to the point where the sub-tree, as this sub-tree roots.

Tree Search : optionally in the drawing undirected depth a node starting the search run, only once per access point, all edges $ (x, y) form a recursion occurred $ tree, called undirected graph search tree .

 

low calculation method :

Shilling $ low [x] = dfn [x] $, considered starting from each edge $ $ x $ (x, y) $

If the search tree is $ $ X $ Y $ parent node, so $ low [x] = min (low [x], low [y]) $

Without the edge $ (x, y) $ is not a search tree edge, so that the $ low [x] = min (low [x], dfn [y]) $

 

Cutting edge decision rule :

Undirected edges $ (x, y) $ are bridged, if and only if a child node exists $ X $ $ Y $ search tree, satisfy: $ dfn [x] <low [y] $

This shows from $ subtree (y) $ departure, without passes $ (x, y) $, no matter which ones sides are unable to reach $ x $ or $ x $ nodes than the earlier visit. If the $ (x, y) $ delete, $ subtree (y) $ on the formation of a closed environment.

Bridge must search tree edge, and a side loop must not simple bridge.

 1 void tarjan(int x, int in_edge)
 2 {
 3     dfn[x] = low[x] = ++num;
 4     int flag = 0;
 5     for(int i = head[x]; i; i = Next[i]){
 6         int y = ver[i];
 7         if(!dfn[y]){
 8             tarjan(y);
 9             low[x] = min(low[x], low[y]);
10             if(low[y] > dfn[x]){
11                 bridge[i] = bridge[i ^ 1] = true;
12             }
13         }
14         else if(i != (in_edge ^ 1)) 
15             low[x] = min(low[x], dfn[y]);
16     }
17 }
18 
19 int main()
20 {
21     cin>>n>>m;
22     tot = 1;
23     for(int i = 1; i <= m; i++){
24         int x, y;
25         scanf("%d%d", &x, &y);
26         if(x == y)continue;
27         add(x, y);
28         add(y, x);
29     }
30     for(int i = 1; i <= n; i++){
31         if(!dfn[i]){
32             tarjan(i, 0);
33         }
34     }
35     for(int i = 2; i < tot; i += 2){
36         if(bridge[i])
37             printf("%d %d\n", ver[i ^ 1], ver[i]);
38     }
39 }

 

Point cut decision rule :

If the root node of the search tree is not a $ X $, then $ X $ is cut point if and only if a child node exists $ X $ $ Y $ search tree, satisfy: $ dfn [x] \ leq low [y] $

In particular, if $ X $ is the root node of the search tree, the $ X $ is cut point if and only if there are at least two conditions described above Y_1 search tree child node $, $ Y_2 satisfied.

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x7fffffff
14 using namespace std;
15 typedef long long LL;
16 typedef pair<int, int> pr;
17 
18 const int SIZE = 100010;
19 int head[SIZE], ver[SIZE * 2], Next[SIZE * 2];
20 int dfn[SIZE], low[SIZE], n, m, tot, num;
21 bool bridge[SIZE * 2];
22 
23 void add(int x, int y)
24 {
25     ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
26 }
27 
28 void tarjan(int x)
29 {
30     dfn[x] = low[x] = ++num;
31     int flag = 0;
32     for(int i = head[x]; i; i = Next[i]){
33         int y = ver[i];
34         if(!dfn[y]){
35             tarjan(y);
36             low[x] = min(low[x], low[y]);
37             if(low[y] >= dfn[x]){
38                 flag++;
39                 if(x != root || flag > 1)cut[x] = true;
40             }
41         }
42         else low[x] = min(low[x], dfn[y]);
43     }
44 }
45 
46 int main()
47 {
48     cin>>n>>m;
49     tot = 1;
50     for(int i = 1; i <= m; i++){
51         int x, y;
52         scanf("%d%d", &x, &y);
53         if(x == y)continue;
54         add(x, y);
55         add(y, x);
56     }
57     for(int i = 1; i <= n; i++){
58         if(!dfn[i]){
59             root = i;
60             tarjan(i);
61         }
62     }
63     for(int i = 1; i <= n; i++){
64         if(cut[i])printf("%d", i);
65     }
66     puts("are cut-vertexes");
67 }

 

Bis communication component

If a cut point is present no connected graph, called the " point-bis FIG communication ." If there is not a bridgeless connected graph, called him " edge double connected graph ."

Undirected graph bis maximum point connected subgraph is referred to as " point-bis connected component ", abbreviated as v-DCC. None is known as "the great side of the sub-bis communication connectivity graph of FIG side communication dual component ", abbreviated as e-DCC.

Theorem 1 a double-point communication is no connected graph of FIG, if and only if one of the following two conditions:

1. The number of vertices is not more than 2 of FIG.

2. FIG any two points are simultaneously included in at least a simple ring.

Theorem 2 a dual-edge connected graph is no connected graph, if and only if any of the at least one side are contained in a simple ring.

Seeking double side connected components

Undirected graph obtained all the bridges, delete bridges, each block communicating communication component is a double edge.

All bridge labeled with Tarjan, and then performs a directed graph for the whole depth-first traversal None (no access bridge), each divided block communication.

 1 int c[SIZE], dcc;
 2 
 3 void dfs(int x){
 4     c[x] = dcc;
 5     for(int i = head[x]; i; i = Next[i]){
 6         int y = ver[i];
 7         if(c[y] || bridge[i])continue;
 8         dfs(y);
 9     }
10 }
11 
12 //main()
13 for(int i = 1; i <= n; i++){
14     if(!c[i]){
15         ++dcc;
16         dfs(i);
17     }
18 }
19 printf("There are %d e-DCCs.\n", dcc);
20 for(int i = 1; i <= n; i++){
21     printf("%d belongs to DCC %d.\n", i, c[i]);
22 }

e-DCC condensing point

The e-DCC shrinkage of a node constituting a new tree stored in another neighbor table.

 1 int hc[SIZE], vc[SIZE * 2], nc[SIZE * 2], tc;
 2 void add_c(int x, int y){
 3     vc[++tc] = y;
 4     nc[tc] = hc[x];
 5     hc[x] = tc;
 6 }
 7 
 8 //main()
 9 tc = 1;
10 for(int i = 2; i <= tot; i++){
11     int x = ver[i ^ 1];
12     y =Ver [I];
 13 is      IF (C [X] == C [Y]) Continue ;
 14      add_c (C [X], C [Y]);
 15  }
 16 the printf ( " forest after condensing points, points% d , the number of edges% d (there may be multiple edges) \ n- " , DCC, TC / 2 );
 . 17  for ( int I = 2 ; I <TC; I ++ ) {
 18 is      the printf ( " % D% D \ n- " , VC [I ^ . 1 ], VC [I]);
 . 19 }

Double point method for finding connected components

Bridge does not belong to any e-DCC, a cut point may belong to a plurality of v-DCC

Tarjan process maintains a stack algorithm, the elements maintain the stack as follows:

1. When a node is first accessed, the node stack.

2. When the cut-point method of determining the conditions in the $ dfn [x] \ leq low [y] $ holds, whether $ x $ is the root, we must:

  (1) continue to pop from the stack node, until a node is ejected $ Y $

  (2) just pop all the nodes and the node $ X $ together form a v-DCC

 1 void tarjan(int x){
 2     dfn[x] = low[x] = ++num;
 3     stack[++top] = x;
 4     iff(x == root && head[x] == 0){
 5         dcc[++cnt].push_back(x);
 6         return;
 7     }
 8     int flag = 0;
 9     for(int i = head[x]; i; i = Next[i]){
10         int y = ver[i];
11         if(!dfn[y]){
12             tarjan(y);
13             low[x] = min(low[x], low[y]);
14             if(low[y] >= dfn[x]){
15                 flag++;
16                 if(x != root || flag > 1)cut[x] = true;
17                 cnt++;
18                 int z;
19                 do{
20                     z = stack[top--];
21                     dcc[cnt].push_back(z);
22 
23                 }while(z != y);
24                 dcc[cnt].push_back(x);
25             }
26         }
27         else low[x] = min(low[x], dfn[y]);
28     }
29 }
30 
31 //main()
32 for(int i = 1; i <= cnt; i++){
33     printf("e-DCC #%d:", i);
34     for(int j = 0; j < dcc[i].size(); j++){
35         printf(" %d", dcc[i][j]);
36     }
37     puts("");
38 }

v-DCC condensing point

 FIG provided a total of $ p $ $ t $ a cut point and a v-DCC, the new map will contain $ p + t $ nodes.

 1 //main
 2 num = cnt;
 3 for(int i = 1; i <= n; i++){
 4     if(cnt[i])new_id[i] = ++num;
 5 }
 6 tc = 1;
 7 for(int i = 1; i <= cnt; i++){
 8     for(int j = 0; j < dcc[i].size(); j++){
 9         int x = dcc[i][j];
10         if(cut[x]){
11             add_c (I, NEW_ID [X]);
 12 is              add_c (NEW_ID [X], I);
 13 is          }
 14          the else C [X] = I;
 15      }
 16  }
 . 17 the printf ( " forest after condensing points, points% d, D number of edges% \ n- " , NUM, TC / 2 );
 18 is the printf ( " No. 1 ~% d is the original v-DCC, number>% d is original cut point \ n- " , CNT, CNT );
 . 19  for ( int I = 2 ; I <TC; I + = 2 ) {
 20 is      the printf ( " % D% D \ n- " , VC [I ^ . 1], U [i]);
21 }

 

There are strongly connected components of the FIG.

A directed graph, if for any two nodes in FIG. $ X, y $, there are both $ X $ $ Y $ path, there are also the $ X $ $ $ Y path, called the digraph It is strongly connected graph .

There is referred to the maximum intensity of the connected subgraphs FIG strongly connected component , abbreviated to SCC.

One of the rings must be strongly connected graph, the basic idea of ​​the algorithm is to Tarjan each point, we can try to find all nodes constituting the ring.

Tarjan while maintaining a depth-first traversal of a stack, when access to the node $ x $, the stack need to save about two types of nodes:

1. Search tree ancestor node $ x $, denoted by $ anc (x) $

2. already visited, and there is a path to the node $ anc (x) $ of

Indeed stack node is enabled nodes and "backward side" $ X $ departing from form a ring and "horizontal cross edge".

Retroactive value:

In order to meet the conditions defined at the nodes of the minimum time stamp:

1. The point in the stack.

2. The presence of a memory subtree (x) departing directed edge to the end point.

calculation steps:

1. When a node $ X $ is first accessed, the $ X $ stack initialization $ low [x] = dfn [x] $

2. Scan starting from each edge $ X $ $ (x, y) $

  (1) If $ Y $ not been visited, then the $ (x, y) $ is the branch side, descend $ Y $, from $ Y $ backtracking, so $ low [x] = min (low [x ], low [y]) $

  (2) If $ Y $ is accessed and the stack $ Y $, so $ low [x] = min (low [x], dfn [y]) $

3. Before $ X $ back, it determines whether $ low [x] = dfn [x] $. If true, the node keeps popping up until $ x $ popped from the stack.

Decision rule strongly connected components

Retroactive value calculation process, if $ x $ back from the front, there is $ low [x] = dfn [x] $ is established, from $ x $ stack to stack all the nodes constituting a strongly connected components.

If $ low [x] = dfn [x] $, description $ subtree (x) $ in the node can not constitute a ring together with other nodes in the stack. Further, since the lateral end timestamp must be less than the starting point side of the fork timestamp, so $ subtree (x) $ a node can not reach the node has not been directly accessible (timestamp larger)

 1 const int N = 100010, M = 1000010;
 2 int ver[M], Next[M], head[N], dfn[N], low[N];
 3 int stack[N], ins[N], c[N];
 4 vector<int>scc[N];
 5 int n, m, tot, num, top, cnt;
 6 
 7 void add(int x, int y){
 8     ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
 9 }
10 
11 void tarjan(int x){
12     dfn[x] = low[x] = ++num;
13     stack[++top] = x, ins[x] - 1;
14     for(int i = head[x]; i; i = Next[i]){
15         if(!dfn[ver[i]]){
16             tarjan(ver[i]);
17             low[x] = min(low[x], low[ver[i]]);
18         }else if(ins[ver[i]]){
19             low[x] = min(low[x], dfn[ver[i]]);
20         }
21     }
22     if(dfn[x] == low[x]){
23         cnt++;
24         int y;
25         do{
26             y = stack[top--], ins[y] = 0;
27             c[y] = cnt, scc[cnt].push_back(y);
28         }while(x != y);
29     }
30 }
31 
32 int main(){
33     cin>>n>>m;
34     for(int i = 1; i <= m; i++){
35         int x, y;
36         scanf("%d%d", &x, &y);
37         add(x, y);
38     }
39     for(int i = 1; i <= n; i++){
40         if(!dfn[i])tarjan(i);
41     }
42 }

Point reduction

 1 void add_c(int x, int y){
 2     vc[++tc] = y, nc[tc] = hc[x], hc[x] = tc;
 3 }
 4 
 5 //main
 6 for(int x = 1; x <= n; x++){
 7     for(int i = head[x]; i; i = Next[i]){
 8         int y = ver[i];
 9         if(c[x] == c[y])continue;
10         add_c(c[x], c[y]);
11     }
12 }

 

 

Li Yudong of "connectivity map to explore some scaling issues" , a little difficult.

Guess you like

Origin www.cnblogs.com/wyboooo/p/11061928.html
Recommended