#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
struct dot {
int cd,next[maxn],child;
}a[maxn];
int n,m,sum,tim[maxn],low[maxn],t;
int fa[maxn];
bool tip[maxn];
int minn(int x,int y) {
if(x <= y) return x;
else return y;
}
void dfs(int z) {
t++;
tim[z]=low[z]=t;
if(a[z].cd != 0) {
for(int i=1;i<=a[z].cd;i++) {
if(tim[a[z].next[i]] == 0) {
a[z].child++; //记录搜索树上的子节点数
fa[a[z].next[i]]=z;
dfs(a[z].next[i]);
if(fa[z] == 0 && a[z].child >= 2 && tip[z] != true) {
tip[z]=true;
sum++;//根节点为割点的判定
}
if(fa[z] != 0 && low[a[z].next[i]] >= tim[z] && tip[z] != true) {
tip[z]=true;
sum++;//非根节点为割点的判定
}
/*
if(low[a[z].next[i]] > tim[i]),则 x->y为桥
*/
low[z]=minn(low[z],low[a[z].next[i]]);//low的维护
}
else if(a[z].next[i] != fa[z]) {
low[z]=minn(low[z],tim[a[z].next[i]]);
//这里用tim是因为a[z].next[i]的low可能是令一个非树边联通的,也就是说会导致z的low变成经过两次非树边结果,与low的定义违背,见如下数据样例
}
}
}
}
int main() {
cin>>n>>m;
for(int i=1;i<=m;i++) {
int x,y;
cin>>x>>y;
a[x].cd++;
a[x].next[a[x].cd]=y;
a[y].cd++;
a[y].next[a[y].cd]=x;
}//无向图的构建
for(int i=1;i<=n;i++) {
if(tim[i] == 0) dfs(i);
}
cout<<sum<<endl;
for(int i=1;i<=n;i++) {
if(tip[i] == true) cout<<i<<" ";
}
return 0;
}
/*
5 6
1 2
1 3
2 3
3 4
3 5
4 5
*/
*割点割桥
最新推荐文章于 2024-09-12 13:19:42 发布