定义
(均在无向图中):在一个连通图中,如果有一个顶点,删除这个点以及相关的边之后,连通块的数量增多,我们就称这个顶点为割点.
算法
tarjan。设有点x及其子节点y,如果x不是是该连通图根节点,那么当且仅当存在dfn[x] <= low[y]时,x为割点。如x为根节点,则至少有满足上式的两个y才能保证x为割点。
解释:
- x不为根节点,x把在x之前遍历的点和在x后遍历的点隔离,则去掉x会是原图不连通而新增连通块。
x为根节点,存在至少两个y表明走任意一个y都不可能到达其他的y。那x被取走后y之间必然互相独立,增加新连通块。
注意:由于判定符号是 <=,则不必考虑重边与父节点。例题 Luogu-P3388
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<algorithm> #define lson x<<1 #define rson x<<1|1 #define ll long long #define rint register int #define mid ((st[x].l + st[x].r) >> 1) using namespace std; template <typename xxx> inline void read(xxx &x) { char c = getchar(),f = 1;x = 0; for(;c ^ '-' && !isdigit(c);c = getchar()); if(c == '-') c = getchar(),f = -1; for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0'); x *= f; } template<typename xxx> inline void print(xxx x) { if(x<0){putchar('-');x=-x;} if(x>9) print(x/10); putchar(x%10+'0'); } const int maxn = 100010; const int inf = 0x7fffffff; const int mod = 1e9 + 7; struct edge{ int to,last; }e[maxn<<1]; int head[maxn],tot; inline void add(int from,int to) { ++tot; e[tot].to = to; e[tot].last = head[from]; head[from] = tot; } int n,m; int dfn[maxn],low[maxn],cnt; int rt,cut[maxn]; inline void tarjan(int x) { low[x] = dfn[x] = ++cnt; int ans = 0; for(rint i = head[x];i;i = e[i].last) { if(!dfn[e[i].to]) { tarjan(e[i].to); if(low[x] > low[e[i].to]) low[x] = low[e[i].to]; if(low[e[i].to] >= dfn[x]) { ++ans; if(x ^ rt || ans > 1) cut[x] = 1; } } else if(low[x] > dfn[e[i].to]) low[x] = dfn[e[i].to]; } } int main() { read(n);read(m);tot = 1; for(rint i = 1;i <= m; ++i) { int a,b; read(a);read(b); if(a == b) continue; add(a,b);add(b,a); } for(rint i = 1;i <= n; ++i) { if(!dfn[i]) { rt = i; tarjan(i); } } int ans = 0; for(rint i = 1;i <= n; ++i) if(cut[i]) ++ans; print(ans),putchar('\n'); for(rint i = 1;i <= n; ++i) { if(cut[i]) print(i),putchar(' '); } return 0; } /* */