Given undirected connected graph:
- For one thing u u u. If deleted from the figure u u u and all u u After u connected edges, the original graph is split into 2 2 Two or more disjointed subgraphs are called u u u is the cut point (or cut top) of the original drawing.
- For one side e e e. If deleted from the figure e e After e, the original image is split into 2 2 Two or more disjointed subgraphs are called e e e is the bridge (or cut edge) of the original drawing.
- The cut points and bridges of a general undirected graph (which does not guarantee connectivity) are the cut points and bridges of its connected blocks.
use T a r j a n \rm Tarjan Tarjan algorithm can be used in O ( n ) \operatorname{O}(n) Find all cut points and bridges in O(n).
Ask S C C \rm SCC Similar to SCC, we also need to use it d f n dfn dfn and l o w low low array, its meaning and solution S C C \rm SCC At SCC d f n , l o w dfn,low DFN is similar to low array.
1. Cutting point
if
u
u
u is not a search tree
r
o
o
t
root
root, then
u
u
u is the cut point if and only if there is at least
u
u
u
1
1
1 child node
v
v
v meet:
d
f
n
(
u
)
≤
l
o
w
(
v
)
dfn(u)\le low(v)
dfn(u)≤low(v)
if
u
u
u is
r
o
o
t
root
root, then
u
u
u is the cut point if and only if
u
u
u at least
2
2
2 child nodes meet the above conditions.
d f n ( u ) ≤ l o w ( v ) dfn(u)\le low(v) dfn(u) ≤ low(v) description s u b t r e e ( v ) subtree(v) subtree(v) departure, if not u u u. You can't get to Darby u u u d f n dfn dfn smaller nodes, then we put u u u delete, and the original picture is divided into two parts s u b t r e e ( v ) subtree(v) subtree(v) and the remaining nodes at least 2 2 2 subgraphs.
P3388 [formwork] cutting point (cutting top)
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 2e4 + 5; const int MAXM = 1e5 + 5; int cnt, Time, rt, tot; int head[MAXN], dfn[MAXN], low[MAXN]; bool cut[MAXN]; struct edge { int to, nxt; }e[MAXM << 1]; void add(int u, int v) { e[++cnt] = edge{v, head[u]}; head[u] = cnt; } void tarjan(int u) { dfn[u] = low[u] = ++Time; //Initialize dfn and low int flag = 0; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!dfn[v]) //The update of low value is similar to that of SCC { tarjan(v); low[u] = min(low[u], low[v]); if (dfn[u] <= low[v]) { flag++; if (u != rt || flag > 1) //x is not the root node, or x is the root node and has at least 2 child nodes that meet the requirements { if (!cut[u]) //Prevent duplicate statistics { tot++; } cut[u] = true; } } } else { low[u] = min(low[u], dfn[v]); } } } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } for (int i = 1; i <= n; i++) { if (!dfn[i]) { tarjan(rt = i); //The root of the search tree is i } } printf("%d\n", tot); for (int i = 1; i <= n; i++) { if (cut[i]) { printf("%d ", i); } } return 0; }
2. Bridge
Search tree
u
u
The child node of u is
v
v
v. Then edge
<
u
,
v
>
<u,v>
< u, V > is a bridge if and only if:
d
f
n
(
u
)
<
l
o
w
(
v
)
dfn(u)<low(v)
dfn(u)<low(v)
d f n ( u ) < l o w ( v ) dfn(u)<low(v) DFN (U) < low (V) description from s u b t r e e ( v ) subtree(v) subtree(v) departure, if not < u , v > <u,v> < u, V >, Darby cannot be reached u u u d f n dfn dfn smaller nodes, then we put < u , v > <u,v> < u, V > is deleted and the original picture is divided into two parts s u b t r e e ( v ) subtree(v) subtree(v) and the remaining nodes at least 2 2 2 subgraphs.
It is worth noting that since it is an undirected edge, from u u u can always go back to it f a fa fa. according to l o w low The definition of low, < u , f a > <u,fa> < u, FA > is near the tree and f a ∉ s u b t r e e ( u ) fa\notin subtree(u) fa ∈ / subtree(u), so d f n ( f a ) dfn(fa) dfn(fa) cannot be used to update l o w ( u ) low(u) low(u)!!!
But do you think it's over?
Tumor data will appear double edge!!!
For heavy edges, there is only one tree edge, so when there are heavy edges, d f n ( f a ) dfn(fa) dfn(fa) can be used to update l o w ( u ) low(u) low(u).
dalao: you ∗ * * blew up
Processing method: store the read edges in pairs
e
(
2
)
e(2)
e(2) and
e
(
3
)
e(3)
e(3),
e
(
4
)
e(4)
e(4) and
e
(
5
)
...
e
(
2
n
)
e(5)\dots e(2n)
e(5)... e(2n) and
e
(
2
n
+
1
)
e(2n+1)
e(2n+1).
Observation:
2 xor 1 = 3 2\,\operatorname{xor}\,1=3 2xor1=3
4 xor 1 = 5 4\,\operatorname{xor}\,1=5 4xor1=5
⋯ ⋯ \cdots\cdots ⋯⋯
2 n xor 1 = 2 n + 1 2n\,\operatorname{xor}\,1=2n+1 2nxor1=2n+1
If passed e ( i ) e(i) e(i) entry u u u, then e ( i ) e(i) e(i) and e ( i xor 1 ) e(i\operatorname{xor}1) e(ixor1) is essentially the same undirected edge, so except e ( i xor 1 ) e(i\operatorname{xor}1) Edges other than e(ixor1) can be used to update l o w ( u ) low(u) low(u).
In addition, Tucao sentence, this problem as a template of the bridge should have been evaluated green, and the result is that the data range is smaller, and it can be used to make complaints about the yellow with violence.
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 155; const int MAXM = 5005; int cnt = 1, Time, tot; //Pay attention here! Because the edge exists in (2,3), (4,5)......, cnt should be initialized to 1! int head[MAXN], dfn[MAXN], low[MAXN]; struct edge { int to, nxt; }e[MAXM << 1]; void add(int u, int v) { e[++cnt] = edge{v, head[u]}; head[u] = cnt; } struct ans { int from, to; bool operator <(const ans &x)const { if (x.from != from) { return x.from > from; } return x.to > to; } }a[MAXM << 1]; void add_ans(int u, int v) { a[++tot] = ans{min(u, v), max(u, v)}; } void tarjan(int u, int in_edge) { dfn[u] = low[u] = ++Time; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!dfn[v]) { tarjan(v, i); low[u] = min(low[u], low[v]); if (dfn[u] < low[v]) //It's a bridge. Save the answers { add_ans(u, v); } } else if (i != (in_edge ^ 1)) //Not the same undirected edge { low[u] = min(low[u], dfn[v]); } } } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } for (int i = 1; i <= n; i++) { if (!dfn[i]) { tarjan(i, 0); } } sort(a + 1, a + tot + 1); //Output according to the topic requirements for (int i = 1; i <= tot; i++) { printf("%d %d\n", a[i].from, a[i].to); } return 0; }
A fun nature
Except for the case of two points and one line, both ends of the bridge must be cut points.