>Link
luogu P3388
>Description
求一张无向图的割点集
>解题思路
按dfs序跑一遍tarjan(那边就分成了树边和回边…),分两种情况
- 根节点:如果它有两个及以上的子树,显然它就是割点
- 非根节点:对于一条边 ( u , v ) (u,v) (u,v),如果 l o w v ≥ d f n u low_v≥dfn_u lowv≥dfnu,那 u u u 就是割点
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
struct edge
{
int to, nxt;
} e[N * 2];
int n, m, cnt, h[N], dfn[N], low[N], tot_ans, ans[2 * N], tot;
void add (int u, int v)
{
e[++cnt] = (edge){
v, h[u]}; h[u] = cnt;
e[++cnt] = (edge){
u, h[v]}; h[v] = cnt;
}
void dfs (int now, int fath)
{
dfn[now] = low[now] = ++tot;
int child = 0;
for (int i = h[now]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fath) continue;
if (!dfn[v])
{
dfs (v, now), low[now] = min (low[now], low[v]);
child++;
if (low[v] >= dfn[now] && fath)
ans[++tot_ans] = now;
}
else low[now] = min (low[now], dfn[v]);
}
if (!fath && child >= 2) ans[++tot_ans] = now;
}
int main()
{
int u, v;
scanf ("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf ("%d%d", &u, &v);
add (u, v);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) dfs (i, 0);
sort (ans + 1, ans + 1 + tot_ans);
tot_ans = unique (ans + 1, ans + 1 + tot_ans) - (ans + 1);
printf ("%d\n", tot_ans);
for (int i = 1; i <= tot_ans; i++)
printf ("%d ", ans[i]);
return 0;
}