题目背景
割点
题目描述
给出一个nn个点,mm条边的无向图,求图的割点。
输入格式
第一行输入n,mn,m
下面mm行每行输入x,yx,y表示xx到yy有一条边
输出格式
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入 #1 复制
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出 #1 复制
1
5
说明/提示
对于全部数据,n \le 20000n≤20000,m \le 100000m≤100000
点的编号均大于00小于等于nn。
tarjan图不一定联通。
给的图不一定是连通图,即求每个联通块的割顶
输出格式别看错了2333
链式前向星开边要2倍
#include<cstdio>
#include<iostream>
#include<stack>
using namespace std;
stack<int>q;
int n,m,cnt,sum,idx;
int dfn[20005],low[20005],in[20005],head[20005],ch[20005];
struct node{
int from,to,next;
}edge[200005];
void add(int from,int to) {
edge[++cnt].from=from;
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void tarjan(int now,int fa){
int son=0;
dfn[now]=low[now]=++idx;
in[now]=1;
q.push(now);
for(int i=head[now];i;i=edge[i].next){
int to=edge[i].to;
if(!dfn[to]){
son++;
tarjan(to,now);
low[now]=min(low[now],low[to]);
if(low[to]>dfn[now]&&!ch[now]){
ch[now]=1;
sum++;
}
}
else if(to!=fa&&dfn[to]<dfn[now]){
low[now]=min(low[now],dfn[to]);
}
}
if(now==fa&&son>=2){
ch[now]=1;
sum++;
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i,i);
}
}
printf("%d\n",sum);
for(int i=1;i<=n;i++){
if(ch[i]){
printf("%d ",i);
}
}
return 0;
}