题目链接:https://www.luogu.org/problem/P3388
割点定义:
1:去掉割点及与其相连的边,原来的连通图不再连通
2:牢记:求割点默认为在无向图中
思路:
1:区别于求强连通分量的tarjan算法
2:求割点的前提是无向图
3:判断是否是割点的两个条件
1:当前节点如果不是根节点,那么只要发现其孩子节点的low值大于等于当前节点的dfn值就可以说明该节点就是割点
if(u!=root&&low[v]>=dfn[u]){
s.insert(u);
}
2:当前节点如果是根节点,那么只要满足有两个孩子节点,那么就可以说明该节点就是割点,因为默认每一个孩子节点之间是不连通的,不然dfs时不会由其中一个孩子节点搜不到另一个孩子节点
if(u==root&&child>1){
s.insert(u);
}
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e4+1;
vector<int> e[maxn];
int dfn[maxn],low[maxn],n,m,x,y;
set<int>s;
int timing;
void tarjan(int u,int root){
timing++;
low[u]=dfn[u]=timing;
int child=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
if(dfn[v]==0){
child++;
tarjan(v,root);
low[u]=min(low[u],low[v]);
if(u!=root&&low[v]>=dfn[u]){
s.insert(u);
}
}
low[u]=min(low[u],dfn[v]);
}
if(u==root&&child>1){
s.insert(u);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
for(int i=1;i<=n;i++)
if(dfn[i]==0) tarjan(i,i);
cout<<s.size()<<endl;
// for(int v:s)
// cout<<v<<" ";
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++){
cout<<*it<<" ";
}
return 0;
}