Statement
This blog is a reference to other blogs, and I added it myself. Good text must be cut to add.
When it comes to the algorithm named Tarjan, we often refer to 3, including the Tarjan algorithm for strong connected components described in this paper. Professor Robert E Tarjan of Princeton University, who presented this algorithm, is also a 1986-year Turing Award winner (see the "Past Turing Award winners" article for specific reasons). first clarify several concepts
Add:
1. Cut point : If a point is deleted, the original connected graph is split into multiple sub-graphs, it is said that the point is a cut point.
2. Cut Point collection : In an undirected connected graph, if there is a vertex set, delete this vertex collection, and all the vertices in this set associated with the edge, the original image becomes a plurality of connected blocks, it is called the point set as a cut point collection.
3. Point Connectivity : The number of vertices in the minimum cut point set.
4. Cut Edge (bridge): After deleting it, the graph will inevitably split into two or more than two sub-graphs.
5. Cut Edge Set : If there is a set of edges, delete this edge set, the original image becomes a plurality of connected blocks, it is called this point set for cutting edge collection.
6. Edge Connectivity : The edge connectivity of a graph is defined as the number of edges in the minimum cut edge set.
7. Pinch point : The non-cutting edge of the connected sub-graph is reduced to a point, at this time to meet any two points between the two path can be reached. NOTE: Block <> indent points. The shrinking point becomes a tree with the k-1 of a K-point and a cut edge. The cut point can exist in more than one block.
8. Dual-connected Components : Divided into two-point double-connected and edge-connected. Its standard definition is: The point connectivity is greater than 1 of the graph is called the point double connected graph, the edge connectivity is greater than 1 of the graph is called edge double connected graph. In layman's words, a graph that satisfies any two-point path that can be reached by two or two or more paths without any repetitive edges is called a double-connected graph. The maximal double-connected sub-graph of undirected graph G is called the double connected component.
Detailed:
1, strong connectivity diagram . In a strong connected graph, any two points are interconnected through a certain path. For example, figure one is a strong connected graph, and figure two is not. Because there is no way to make point 4 reach point 1, 2 or 3.
2, strong connectivity components . In a non-strong connected graph, the strongly connected sub-graph is the strong connected component of the graph. For example, the figure three neutron diagram {1,2,3,5} is a strongly connected component, and the sub-diagram {4} is a strongly connected component.
the application of Tarjan algorithm is discussed:
1. Finding strong connected components, cutting points, bridges, and shrinking points:
For the Tarjan algorithm, we get a dfn and a low two arrays,
low[u]:=min (Low[u],dfn[v])--(U,V) is a back edge, V is not a subtree of u; low[u]:=min (Low[u],low[v])--(U,V) is the branch edge, V is the subtree of U;
below to discuss it:
if low[v]>=dfn[u], then U is the cut point, U and its descendants form a block.
Because this means that the descendants of U cannot reach the ancestors of U through the other side, so that after you remove U, the graph must be divided into two sub-graphs.
if Low[v]>dfn[u], then (u,v) for cutting edge . The reason is similar to the previous case.
In fact, the Tarjan algorithm is based on DFS. We prepare two arrays of low and dfn**. The low array is an array of tokens that record the DFN value of the root node of the search subtree where the strong connected sub-graph is located (very Raozui, as you will see), **DFN the time the array records the search to that point, that is, the first few searches for this point . According to the following rules, after searching through the graph (no backtracking) and the operation of the stack, we can get the strong connected component of the forward graph.
Initialization of the array: when the first search point P, the value of the DFN and the low array is the time of the dot.
Stack: Every search to a point, press it into the top of the stack.
When the point P is connected to the point P ', if at this time (Dfn[p]) p ' is not in the stack, P's low value is the smaller of the lower value of two points.
When the point P has a connection to the point P ', if at this point (time is dfn[p]) p ' in the stack, P's low value is the lower value of P and the smaller of P ' 's DFN value.
Whenever the search to a point passes above (that is, the subtree has been all traversed) the low value equals the DFN value, then it pops up the stack along with the element above it. These elements of the stack form a strong connected component.
Continue searching (you may change the starting point of the search, because the entire graph may be divided into two disconnected parts) until all points are traversed.
Since each vertex is accessed only once, and each edge is accessed only once, we can find the strongly connected component of the graph in O (n+m) time. But what is the reason for doing this? The operating principle of the Tarjan algorithm is as follows :
The
Tarjan algorithm is based on the theorem: in any depth-first search, all vertices within the same strong connected component are in the same depth-first search tree. in other words, the strongly connected component must be a deep search tree subtree of the graph. The
proves that when a point is both a point in a strongly connected sub-graph Ⅰ and a point in a strongly connected Ⅱ, it is a point in the strongly connected sub-graph Ⅰ∪ⅱ.
In this way, we use the low value to record the DFN value of the root node of the search subtree corresponding to the strong connected sub-graph of the point. Note that the elements in the subtree must be contiguous in the stack, and the root node must be at the bottom of all the subtree elements in the stack. The
strongly connected component is made up of several rings. So, when a loop is formed (that is, the next point in the search is already in the stack), we unify the low value of this path, that is, the points on this path belong to the same strong connected component.
If the DFN value of a point is equal to the low value after traversing the entire search tree, it is the root of the search subtree. at this point, all the elements above (including itself) to the top of the stack form a strong connected component.
Tarjan the code for the strong connected component, cutting point and cutting edge of the graph: Var n,m,i,j,x,y,z:longint;
A,b:array[0..1000,0..1000]of longint;//diagram Dfn,low,s:array[0..1000]of LONGINT;//DFN is timestamp, low is ancestor, S is stack
Vis,ins:array[0..1000]of Boolean;//vis for whether to access, ins for whether in the stack num,p:longint;
function min (x,y:longint): Longint;
Begin if X<y then exit (x) Else exit (y);
End
Procedure Tarjan (U:longint);
var i,v:longint;
Begin Inc. (NUM);//given a timestamp dfn[u]:=num;
Low[u]:=num;
Vis[u]:=true;
Inc (P);//into the stack s[p]:=u;
Ins[u]:=true;
For I:=1 to b[u,0] do//note that only u and I are connected for the following operation if not Vis[b[u,i]] then//is not visited begin Tarjan (B[u,i]); Low[u]:=min (Low[u],low[b[u,i]);//Is the branch edge, take two low min value {if is cut point or cut edge, here Judge Dfn[u] and Low[v] size and the stack can be.
} end else if Ins[b[u,i]] then//in the stack low[u]:=min (low[u],dfn[b[u,i]);//non-branch edge, take low and DFN min value
If Dfn[u]=low[u] then//has found a strong connected component, the bounce stack.
Repeat v:=s[p]; Write (V, ");
Ins[v]:=false;
Dec (p);
If U=v then Writeln;
Until U=v;
End
Begin READLN (N,M);
For I:=1 to M do//composition begin READLN (x, y);
Inc (b[x,0]);
B[x,b[x,0]]:=y;
End
Tarjan (1); End.
2. To find two connected components and to construct a two-connected component:
For the point double connected branch, in fact in the process of finding a cut point can be in the way of each point two connected branches to find out.
Create a stack that stores the current two connected branches and, when searching for a graph, adds the edge to the stack by finding a branch or back edge (not a cross-border). If a DFS (U) <=low is encountered at some time, it means that U is a cut point, and the edges are removed from the top of the stack at the same time, until an edge (U,V) is encountered, and the points that are taken out of these edges are connected to each other, forming a point -double-connected branch.
A cut point can belong to multiple points of two connected branches , and the remaining points and each edge belong to and belong to only one point double connected branch .
For the side double connected branch, the method is easier to find. Just after all the bridges have been found, the bridge edge is removed and the original image becomes a plurality of connected blocks, and each connected block is a double connected branch of the edge. The bridge does not belong to any one-side double-connected branch, and the rest of the edges and each vertex belong to and belong to only one edge, two connected branches.
A connected graph with a bridge, how to turn it into a double connected graph by adding edges.
The method is to first find all the bridges and then delete the bridge edges, and each of the remaining connected blocks is a double-connected sub-graph. Each double-connected sub-graph is shrunk to a vertex, and then the bridge is added back, the last figure must be a tree, the edge connectivity is 1.
The number of nodes in the tree is 1, that is, the number of leaf nodes, which is recorded as Leaf.
Then at least add (leaf+1)/2 edges to the tree to make the tree reach the edge two, so at least the number of edges added is (leaf+1)/2.
The method is to first connect an edge between the two nearest common ancestor's two leaf nodes, so that the two points can be shrunk to the path of the ancestors, because a formed ring must be double connected. Then find the two nearest public ancestor the furthest two leaf nodes, so that a pair to find out, happens to be (leaf+1)/2 times, all the points are shrunk together.
3. Finding the nearest public ancestor (LCA)
When traversing to u, first tarjan the subtree of U, then the nearest public ancestor of the nodes in the subtree of U and U is u, and the nearest public ancestor of U and "U's sibling node and its subtree" is the father of U. Notice that since we are traversing in DFS order, we can use a color array tag that is being accessed with a stain of 1, an unreachable token of 0, which has been accessed in the " u subtree " and " U's visited sibling node and its subtree" The stain is labeled 2 so that we can achieve these goals through find by constantly merging updates with the check set. Code
function Find (x:longint): Longint;
Begin
If F[x]<>x then F[x]:=find (F[x]);
End;
Procedure Tarjan (u:longint);
Begin
F[u]:=u;
For I:=1 to N does
if (G[u,i]) and (color[i]=0) then//g[u,i] means U is attached to I
begin
F[i]:=u;
End;
For I:=1 to n do
if ((Ask[u,i]) or (Ask[i,u]) and (color[i]=2) then//ask[u,i] means asked u,i
begin
Lca[u,i]:= Find (i);
Lca[i,u]:=lca[u,i];
End;
color[u]:=2;
End
An example (I forgot the number of the question) CODE
#include <cstdio> #include <iostream> #define N 50001 #define LL Long long #define FO (i,a,b) for (int i=a;i<
; =b;i++) using namespace std;
int dfn[n],low[n],zhan[n];
BOOL V[n];
int t[2*n],next[2*n],last[2*n];
int n,m,l,top=0;
LL ans=0;
void Add (int x,int y) {t[++l]=y;
NEXT[L]=LAST[X];
Last[x]=l;
} void Tarjan (int x) {zhan[++top]=x;
Dfn[x]=++l;
Low[x]=l;
int k=last[x];
Bz[x]=true;
V[x]=true;
while (k!=0) {if (dfn[t[k]]==0) {Tarjan (t[k]);
if (Low[t[k]]<low[x]) low[x]=low[t[k]];
} else if (V[t[k]] && dfn[t[k]]<low[x]) low[x]=dfn[t[k];
K=NEXT[K];
} if (Low[x]==dfn[x]) {LL xdl=0;
while (zhan[top+1]!=x) {v[zhan[top]]=false;
top--;
xdl++;
} ans+= (XDL-1) *XDL/2;
}} int main () {scanf ("%d%d", &n,&m);
int x, y; Fo (i,1,m) {scanf ("%d%d", &x,&y);
Add (x, y);
} l=0;
FO (i,1,n) if (not Bz[i]) Tarjan (i);
printf ("%d", ans); }