[Study notes] Unicom component

"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.

image


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 ~~

Guess you like

Origin www.cnblogs.com/Paranoid-LS/p/11325802.html