题目描述
给出一个n个点,m条边的无向图,求图的割点。
输入格式:
第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
输出格式:
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入样例:
6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6
输出样例:
1 5
说明
n,m均为100000
tarjan 图不一定联通!!!
题解
裸的tarjan模板。一个点为割点:1.不为根节点且dfn[now]<=low[e[i].to] 2.为根节点且有超过两个子树
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 struct node 7 { 8 int next,to; 9 } e[200005]; 10 int head[100005],cut[100005],cnt=1,from[100005]; 11 int dfn[100005],low[100005],time; 12 inline void insert(int u,int v) 13 { 14 e[++cnt].next=head[u]; 15 head[u]=cnt; 16 e[cnt].to=v; 17 } 18 inline void tarjan(int now,int rt) 19 { 20 int num=0; 21 dfn[now]=low[now]=++time; 22 for(int i=head[now];i;i=e[i].next) 23 { 24 if(i==(from[now]^1)) continue; 25 if(!dfn[e[i].to]) 26 { 27 from[e[i].to]=i; 28 tarjan(e[i].to,rt); 29 low[now]=min(low[now],low[e[i].to]); 30 if(dfn[now]<=low[e[i].to] && now!=rt) cut[now]=1; 31 if(now==rt) num++; 32 } 33 else low[now]=min(low[now],dfn[e[i].to]); 34 } 35 if(now==rt && num>=2) cut[now]=1; 36 } 37 int main() 38 { 39 int n,m,u,v,ans=0; 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=m;i++) 42 { 43 scanf("%d%d",&u,&v); 44 insert(u,v); 45 insert(v,u); 46 } 47 for(int i=1;i<=n;i++) 48 if(!dfn[i]) tarjan(i,i); 49 for(int i=1;i<=n;i++) if(cut[i]) ans++; 50 printf("%d\n",ans); 51 for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i); 52 return 0; 53 }