题目背景
割点
题目描述
给出一个n个点,m条边的无向图,求图的割点。
输入输出格式
输入格式:第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
输出格式:第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入样例#1:
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出样例#1:
1
5
说明
n,m均为100000
tarjan 图不一定联通!!!
注意与tarjan 求强连通分量的方法区别。
求割点不需要用到栈。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 int N,M,x,y,cnt,Index,ans=0; 9 int first[100010],next[200010]; 10 int dfn[100010],low[100010]; 11 bool del[100010]; 12 13 struct maple{ 14 int f,t; 15 }Rode[200010]; 16 17 void Build(int f,int t) 18 { 19 Rode[++cnt]=(maple){f,t}; 20 next[cnt]=first[f]; 21 first[f]=cnt; 22 } 23 24 void Tarjan(int n,int fa) 25 { 26 int cd=0; 27 dfn[n]=low[n]=++Index; 28 for(int i=first[n];i;i=next[i]) 29 { 30 if(!dfn[Rode[i].t]) 31 { 32 Tarjan(Rode[i].t,n); 33 low[n]=min(low[n],low[Rode[i].t]); // 更新n能向上回溯到的最小时间戳 34 if(low[Rode[i].t]>=dfn[n]&&fa!=-1) // 如果n的子树中最多能追溯到n,并且n不为根的话, 35 del[n]=1; //就为一个割点,根要特殊处理 36 if(fa==-1) ++cd; // 统计根的子树 37 } 38 else if(Rode[i].t!=fa) low[n]=min(low[n],dfn[Rode[i].t]); 39 } 40 if(fa==-1&&cd>=2) del[n]=1; // 如果n为根且n的子树数量大于等于 2 ,即为一个割点 41 } 42 int main() 43 { 44 scanf("%d%d",&N,&M); 45 for(int i=1;i<=M;++i) 46 { 47 scanf("%d%d",&x,&y); 48 Build(x,y); 49 Build(y,x); 50 } 51 for(int i=1;i<=N;++i) 52 if(!dfn[i]) Tarjan(i,-1); 53 for(int i=1;i<=N;++i) if(del[i]) ++ans; 54 printf("%d\n",ans); 55 for(int i=1;i<=N;++i) 56 if(del[i]) 57 printf("%d ",i); 58 return 0; 59 }