首先,我们要了解一下割点的定义:把这个点去掉之后,这个点所在的联通块就会被分成若干个联通块。
既然这样,也就是说,只要这个节点某一个子节点所到达的节点的dfsdfsdfs序大于等于该节点的dfsdfsdfs序,即它的这个子节点无法到达dfsdfsdfs序小于该节点的节点,就说明它是一个割点了。
而对于一个联通块第一个访问的节点,则需特判,如果它在遍历完一个节点所能遍历到的所有节点,还能找到没有被遍历过的节点,就说明它是一个割点。
#include<iostream>
#include<cstring>
using namespace std;
struct edge{
int v,fail;
edge(){
}
edge(int a,int c){
v=a;
fail=c;
}
}e[200100];
int len,head[200100];
int num,vis[200100];
void add(int a,int b){
e[len]=edge(b,head[a]);
head[a]=len++;
}
int ti,dfn[200100],low[200100];
void tarjan(int now,int fa){
low[now]=dfn[now]=++ti;
int cnt=0;
for(int i=head[now];~i;i=e[i].fail){
if(e[i].v==fa)
continue;
if(!dfn[e[i].v]){
cnt++;
tarjan(e[i].v,now);
low[now]=min(low[now],low[e[i].v]);
if(low[e[i].v]>=dfn[now]){
if(fa>0)
vis[now]=1,num++;
}
}
else
low[now]=min(low[now],dfn[e[i].v]);
}
if(fa<0&&cnt>=2)
vis[now]=1,num++;
}
int main(){
//freopen("a.in","r",stdin);
memset(head,-1,sizeof(head));
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b;
add(a,b);
add(b,a);
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i,-1);
}
//cout<<num<<endl;
int cnt=0;
for(int i=1;i<=n;i++)
if(vis[i])cnt++;
//cout<<i<<" ";
cout<<cnt<<endl;
for(int i=1;i<=n;i++){
if(vis[i])cout<<i<<" ";
}
cout<<endl;
return 0;
}