题目描述
给出一个nn个点,mm条边的无向图,求图的割点。
输入格式
第一行输入n,mn,m
下面mm行每行输入x,yx,y表示xx到yy有一条边
输出格式
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入
6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6
输出
1 5
说明/提示
对于全部数据,n≤20000,m≤100000
点的编号均>0,<=n
tarjan图不一定联通
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e5+5; 5 int low[N],dfn[N]; 6 vector<int> g[N];///邻接表存图 7 set<int> st;///存割点 8 int tot,n,m; 9 10 void tarjan(int u,int father){ 11 int v,child=0; 12 dfn[u]=low[u]=++tot; 13 for(int i=0;i<g[u].size();i++){ 14 v=g[u][i]; 15 if(v==father) continue; 16 if(dfn[v]==0){///点未被访问过 17 tarjan(v,u); 18 low[u]=min(low[u],low[v]); 19 if(u==father){///根节点统计子树数量 20 child++; 21 } 22 else{ 23 if(low[v]>=dfn[u]){ 24 st.insert(u); 25 } 26 } 27 } 28 else{ 29 low[u]=min(low[u],dfn[v]); 30 } 31 } 32 if(u==father&&child>=2){///为根节点且子树数量大于1,为割点 33 st.insert(u); 34 } 35 } 36 37 int main(){ 38 int x,y; 39 scanf("%d%d",&n,&m); 40 while(m--){ 41 scanf("%d%d",&x,&y); 42 g[x].push_back(y);///无向图,存双向边 43 g[y].push_back(x); 44 } 45 for(int i=1;i<=n;i++){ 46 if(dfn[i]==0){ 47 tot=0; 48 tarjan(i,i); 49 } 50 } 51 printf("%d\n",st.size()); 52 int flag=0; 53 for(set<int>::iterator it=st.begin();it!=st.end();it++){ 54 if(flag==0) flag=1; 55 else printf(" "); 56 printf("%d",*it); 57 } 58 printf("\n"); 59 }