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.