"Tarjan accompanied by strong component of China Unicom
after the completion of the spanning tree idea was flash
Seven Bridges ran the Euler gutang
make you fascinated" ---- "You copy the film"
A, tarjan seeking to communicate with a component Tuqiang
① the definition of strongly connected components
In a directed graph G, if two vertices vi, vj between \ ((vi> vj) \) the path has a directional path from vi to vj, along a path from vi to vj are then He said two vertices strongly connected (strongly connected). If there are strongly connected to each of the two vertices of G, said G is a strongly connected graph . There are a great strength to FIG connected subgraph, called strongly connected components (strongly connected components).
We find that there is a maximum of drawing the figure, so this figure can reach each other every two points. This maximum strongly connected component referred to in FIG, but also belong to a point strongly connected components.
Strongly connected component ② Method
tarjan algorithm, nonsense
Auxiliary array:
dfn [i]: i is the first of several point to search;
low [i]: all points and descendant node point i dfn even in minimum;
stack [i]: Now all points may constitute the strongly connected components;
in [i]: i is the point Stack [] array;
Code:
vector <int> scc[N];
int sta[N], tp, dfn[N], low[N], tot, in[N], cnt, tar[N];
void tarjan(int x) {
dfn[x] = low[x] = ++ tot;
sta[++ tp] = x; in[x] = 1;
for(int i = head[x]; i ;i = e[i].nxt) {
if(! dfn[e[i].to])
tarjan(e[i].to), low[x] = min(low[x], low[e[i].to]);
else if(in[e[i].to])
low[x] = min(low[x], dfn[e[i].to]);
if(dfn[x] == low[x]) {
int y; cnt ++;
do {
y = sta[tp --], in[y] = 0;
tar[y] = cnt, scc[cnt].push_back(y);
}while(x != y);
}
}
}
Second, the contraction point
Condensing point ① use
The DAG has Honey Fans of superiority, you can safely run dfs, chaos dp.
But if there is to have a DAG, you do not hit the mark vis, you dfs ah ~, dp it ~
If you do not hit the mark vis t will fly, even if the marking, there is no guarantee that the optimal solution ~ ~
At this point in relation to shrink.
② point reduction method
Condensing point in question differs in different processing method.
All shrink Point Method:
Enumeration each side (original image), to check whether the two terminals in the same communication within a strong component.
If not operated; otherwise, even in the strongly connected component edges.
Code:
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i);
for (int x = 1; x <= n; x++)
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (c[x] == c[y]) continue;
add_c(c[x], c[y]);
}
}
Third, the cutting edge / Bridge
① cutting edge concept
In the drawing undirected, wherein if an edge is removed, FIG no longer in communication, then this edge is called the cutting edge .
② cutting edge algorithm Tarjan
\ (low [v]> dnf [u] \) Description \ (UV \) is the bridge
As proof, I suggest to ask Tarjan himself . . . . . .
code:
void tarjan(int x, int in_edge) {
dfn[x] = low[x] = ++num;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (!dfn[y]) {
tarjan(y, i);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x])
bridge[i] = bridge[i ^ 1] = true;
}
else if (i != (in_edge ^ 1))
low[x] = min(low[x], dfn[y]);
}
}
Fourth, cut point
① cut concept points
Undirected connected graphs, in which if a connection point and this point all edges removed, FIG no longer in communication, then this point is called the cut point (Cut Vertex / articulation Point) .
② cut point Tarjan algorithm
Algorithmic process:
First select a root node from the root node to traverse the entire map (DFS).
For the root node : calculating its subtree, if there are two or more subtrees that cut.
For non-root nodes : maintain two arrays dfn [] and low []. For the edge (u, v), if the \ (Low [V]> = DFN [u] \) , u is cut at this time point.
Calculating low [u] of the method:
Suppose the current vertex u, default \ (Low [U] = DFN [U] \) , i.e., only the first back to itself.
There is an edge (u, v), then if V (non-fa) unvisited, continue DFS, DFS finished, \ (Low [U] = min (Low [U], Low [V]) \) ;
If V (non-fa) visited, there is no need to continue the DFS, there must be \ (DFN [V] <DFN [U] \) , \ (Low [U] = min (Low [U], DFN [V] ) \) .
code:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 5;
struct edge{ int to, nxt; }e[N << 1];
int n, m, idx, cnt, tot;
int head[N], dfn[N], low[N];
bool cut[N];
void add(int from, int to) {
e[++ cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
void tarjan (int x,int fa) {
dfn[x] = low[x] = ++ idx;
int child = 0;
for (int i = head[x]; i ;i = e[i].nxt) {
int to = e[i].to;
if (! dfn[to]) {
tarjan (to, fa);
low[x] = min (low[x], low[to]);
if (low[to] >= dfn[x]&&x != fa) cut[x] = 1;
if(x == fa) child ++;
}
low[x] = min (low[x], dfn[to]);
}
if (child >= 2&&x == fa) cut[x] = 1;
}
int main() {
scanf ("%d%d", &n, &m);
for(int i = 1, x, y;i <= m;i ++) {
scanf ("%d%d", &x, &y);
add (x, y); add (y, x);
}
for(int i = 1;i <= n;i ++)
if(dfn[i] == 0) tarjan (i,i);
for(int i = 1;i <= n;i ++)
if(cut[i]) tot++;
printf ("%d\n", tot);
for(int i = 1;i <= n;i ++)
if (cut[i]) printf("%d ", i);
return 0;
}
Five point cut relations with the cutting edge
① a cut point is not necessarily a bridge, a bridge there must be a cut point.
② bridge is not necessarily the point of attachment of the cut edge.
FIG vertex C as the cut point, but the edges are not connected to C, and the bridge.
Five examples
Los ball cattle trough P2863 : tarjan number with the number of the strongly connected components, each point to stained strongly connected components, can count the number of each strongly connected component of a midpoint, if more than one, the answer plus a
P2341 [HAOI2006] popular cattle : ----------------------------------------- > problem solution poke me
Luo Valley P3387 template condensation point : shrunk to a strongly connected component of each point, the weight is strongly connected component and the values of all the points, DFS running, add memory search if the complexity is \ (O (n) \ ) of
Luo Gu P3388 template cut point : the point of seeking to cut the number and location
Tarja's 求 LCA
First, image understanding
Bear a child
zh_dou__ wfx the most from a bottom of the leftmost root of the tree nodes irrigation magma, __ wfx represents hate this backwards-long tree. Magma will continue injecting until the entire tree filled ... If the magma filled with sub-tree, __ wfx found on the other side of the tree have a deeper sub-tree, __ wfx will go to the sub-tree tree filled. Magma will only rise up in compelling circumstances, to find a new sub-trees continue to inject. Machine (yu) Chile (chun) of __wfx found a good way to find the LCA, that if two nodes are lava burned, LCA their position is the highest tree in the sub-tree magma.
Second, implementation
—— I will direct the code ah ~
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e6 + 5;
struct node{ int nxt,to; }e[N];
struct node2{ int id, to, nxt; }que[N];
int head[N], cnt;
void add(int u, int v){
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int ans[N], head_[N], cnt_;
void add_q(int u,int v,int i){
que[++cnt_].to = v;
que[cnt_].id = i;
que[cnt_].nxt = head_[u];
head_[u] = cnt_;
}
int n, m, s, fa[N], vis[N], lca[N];
int find(int x){ return x == fa[x] ? fa[x] : fa[x] = find(fa[x]); }
void tarjan(int u){
vis[u] = 1;
for(int i = head[u]; i ;i = e[i].nxt){
int v = e[i].to;
if(! vis[v]) tarjan(v), fa[v] = find(u);
}
for(int i = head_[u]; i ;i = que[i].nxt){
int v = que[i].to;
if(vis[v]) lca[que[i].id] = find(v);
}
}
int main(){
scanf("%d%d%d", &n, &m, &s);
for(int i = 1, a, b;i < n;i ++){
scanf("%d%d", &a, &b);
add(a,b); add(b,a);
}
for(int i = 1, a, b;i <= m;i ++){
scanf("%d%d", &a, &b);
add_q(a,b,i); add_q(b,a,i);
}
for(int i = 1;i <= n;i ++) fa[i] = i;
tarjan(s);
for(int i = 1;i <= m;i ++) printf("%d\n", lca[i]);
return 0;
}
Third, examples
P3379 [template] recent common ancestor (LCA) : example, did not have to run ~~