版权声明:布呗之路的守望者 https://blog.csdn.net/hypHuangYanPing/article/details/81986100
/**
洛谷3388 计算割点的数量及割点
割点:拆点后图不连通的点 根:child>=2 非: low[v]>=dfn[u];
割桥:割点出度方向所连的边;一般用pair进行存储;
*/
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=1e5+7;
int top,bcnt,dcnt;
int sta[maxn],dfn[maxn],low[maxn],belong[maxn];
bool ins[maxn];
int out[maxn];
int u,v,n,m;
std::vector<int> G[maxn];
std::vector<int> GG[maxn];
int parent[maxn];//节点关系;
int iscut[maxn];//当前节点是否为割点;
int cut_num;//割点数量;
void dfs(int u){
dfn[u]=low[u]=++dcnt;
ins[u]=true;
sta[top++]=u;
int child=0;
for(int v:G[u]){
if(dfn[v]==0) {
child++;
parent[v]=u;
dfs(v);
low[u]=min(low[u],low[v]);
if((!iscut[u]&&parent[u]!=-1&&low[v]>=dfn[u])||(parent[u]==-1&&child>=2&&!iscut[u])) iscut[u]=1,cut_num++;
//非根节点low[v]>=dfn[u];当前节点为根节点 且出度为2
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
/*******************************缩点操作部分 栈记录可能构成强联通分量的点**************/
if(dfn[u]==low[u]) {
++bcnt;
int pos;
do{
pos=sta[--top];
ins[pos]=false;
belong[pos]=bcnt;
}while(pos!=u);
}
return ;
}
void tarjan(){
bcnt=top=dcnt=cut_num=0;
memset(dfn,0,sizeof(dfn));
memset(ins,0,sizeof(ins));
memset(out,0,sizeof(out));
memset(iscut,0,sizeof(iscut));
memset(parent,-1,sizeof(parent));
for(int i=1;i<=n;i++) if(dfn[i]==0) dfs(i);
/***缩点后图变为GG操作*********************************/
for(int i=1;i<=n;i++) GG[i].clear();
for(int i=1;i<=n;i++){
for(int pos:G[i]){
int u=belong[i];
int v=belong[pos];
if(u!=v) GG[u].push_back(v),++out[u];
}
}
}
int main () {
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
tarjan();
printf("%d\n",cut_num);//割点的数量;
for(int i=1;i<=n;i++) {
if(iscut[i]){
cut_num--;
printf(cut_num==0?"%d\n":"%d ",i);
}
}
return 0;
}