<学习笔记> tarjan 求割点(割顶)

go to the problem

割点:在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合
如果某个割点集合只含有一个顶点X(也即{X}是一个割点集合),那么X称为一个割点。

题目背景

割点

题目描述

给出一个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 }

 

posted @ 2017-11-07 19:05  loi_maple  阅读(271)  评论(0)    收藏  举报