题目描述
给出一个 n 个点,m 条边的无向图,求图的割点。
输入格式
第一行输入两个正整数 n,m。
下面 m 行每行输入两个正整数 x,y 表示 x 到 y 有一条边。
输出格式
第一行输出割点个数。
第二行按照节点编号从小到大输出节点,用空格隔开。
输入输出样例
输入
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出
1
5
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int h[maxn], dfn[maxn], low[maxn], b[maxn], s[maxn];
int cnt, tot, n, m, num;
struct edge{
int v, next;
}e[maxn];
void addedge(int u, int v)
{
e[tot].v = v;
e[tot].next = h[u];
h[u] = tot++;
}
void tarjan(int u, int fa)
{
dfn[u] = low[u] = ++cnt;
for(int i = h[u]; i != -1; i = e[i].next){
int v = e[i].v;
if(!dfn[v]){
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
b[u]++;
}
else
low[u] = min(low[u], dfn[v]);
}
if(fa && b[u]) // 不是根节点的情况,至少得有一个子节点
s[++num] = u;
if(!fa && b[u] > 1) // 是根节点,子节点的个数大于 1
s[++num] = u;
}
int main()
{
memset(h, -1, sizeof(h));
cin >> n >> m;
for(int i = 1; i <= m; i++){
int a, b;
cin >> a >> b;
addedge(a, b);
addedge(b, a);
}
for(int i = 1; i <= n; i++){
if(!dfn[i])
tarjan(i, 0);
}
sort(s + 1, s + num + 1);
cout << num <<endl;
for(int i = 1; i <= num; i++)
cout << s[i] << " ";
return 0;
}