题目描述
给出一个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 n,m,dep; 6 int dfn[N],low[N]; 7 vector<int> g[N];///邻接表存图 8 set<int> st;///存割点 9 10 void tarjan(int u,int father){ 11 dfn[u]=low[u]=++dep; 12 int child=0; 13 for(int i=0;i<g[u].size();i++){ 14 int v=g[u][i]; 15 if(!dfn[v]){///点未被访问过 16 tarjan(v,father); 17 low[u]=min(low[u],low[v]); 18 if(u==father){///根节点统计子树数量 19 child++; 20 } 21 else{ 22 if(dfn[u]<=low[v]) 23 st.insert(u); 24 } 25 } 26 else low[u]=min(low[u],dfn[v]); 27 } 28 if(u==father&&child>=2)///为根节点且子树数量大于1,为割点 29 st.insert(u); 30 } 31 32 int main(){ 33 scanf("%d%d",&n,&m); 34 while(m--){ 35 int x,y; 36 scanf("%d%d",&x,&y); 37 g[x].push_back(y);///无向图,存双向边 38 g[y].push_back(x); 39 } 40 for(int i=0;i<n;i++){ 41 dep=0;///图未必连通,每次置为0 42 if(!dfn[i]){ 43 tarjan(i,i); 44 } 45 } 46 printf("%d\n",st.size()); 47 int flag=0; 48 for(set<int>::iterator it=st.begin();it!=st.end();it++){ 49 if(flag) printf(" "); 50 else flag=1; 51 printf("%d",*it); 52 } 53 printf("\n"); 54 }