注意如果题目要求割点的个数的话,一定不能在tarjan算法中去统计,会导致单个点被重复统计多次,导致答案比实际多。应该在对所有点求完tarjan以后(因为图可能不是联通的),在记录每个点是否是割点的数组中扫描一遍去统计。
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
const int N=20100,M=201010;
inline int read(){
register int v=0,sign=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') break;
if(ch=='-') sign=1; else v=ch-48;
while(isdigit(ch=getchar())) v=v*10+ch-48;
if(sign==1) return -v; else return v;
}
int nxt[M],to[M],head[N],len;
inline void addedge(int a,int b){
nxt[++len]=head[a]; head[a]=len; to[len]=b;
}
int n,m,ans;
int nowroot,dfn[N],tme,low[N];
bool isgedian[N];
void tarjan(int v){
dfn[v]=low[v]=++tme;
int cnt=0;
for(int i=head[v];i!=-1;i=nxt[i]){
int u=to[i];
if(!dfn[u]){
cnt++;
tarjan(u);
low[v]=min(low[v],low[u]);
if((v==nowroot&&cnt>1)||(v!=nowroot&&low[u]>=dfn[v])) isgedian[v]=true;
//不可以直接在这里统计割点个数 !!!因为循环的缘故,一个点可能会被计算多次,导致个数错误
}else low[v]=min(low[v],dfn[u]);
}
}
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m;
rep(i,1,m){
int a,b;
cin>>a>>b;
addedge(a,b); addedge(b,a);
}
rep(i,1,n) if(!dfn[i]) nowroot=i,tarjan(i);
rep(i,1,n) if(isgedian[i]) ans++;
cout<<ans<<endl;
rep(i,1,n) if(isgedian[i]) cout<<i<<' ';
return 0;
}