洛谷—— P3388 【模板】割点(割顶)
题目背景
割点
题目描述
给出一个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 图不一定联通!!!
唉,题如题目。。
大水题!!!!
代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 200009 using namespace std; bool cut_point[N]; int x,y,n,m,tot,ans,tim; int dfn[N],low[N],head[N]; struct Edge { int from,next,to; }edge[N]; void add(int x,int y) { tot++; edge[tot].next=head[x]; edge[tot].to=y; head[x]=tot; } int tarjan(int now,int pre) { int sum=0;bool boo=false; dfn[now]=low[now]=++tim; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(i==(1^pre)) continue; if(!dfn[t]) { sum++; tarjan(t,i); low[now]=min(low[now],low[t]); if(low[t]>=dfn[now]) boo=true; } else low[now]=min(dfn[t],low[now]); } if(!pre){if(sum>1) ans++,cut_point[now]=true;} else if(boo) ans++,cut_point[now]=true; } int main() { tot=1; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0); printf("%d\n",ans); for(int i=1;i<=n;i++) if(cut_point[i]) printf("%d ",i); return 0; }