题目背景
割点
题目描述
给出一个n个点,m条边的无向图,求图的割点。
输入输出格式
输入格式:
第一行输入n,m
下面m行每行输入x,y表示x到y有一条边
输出格式:
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
说明
n,m均为100000
tarjan 图不一定联通!!!
注意这题实际数据范围比题目描述要大。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 const int MAXN = 1e5 + 7; 5 const int MAXM = 2e5 + 7; 6 7 int n, m, first[MAXN], sign, indx, scc; 8 9 int dfn[MAXN], low[MAXN], ins[MAXN], cut[MAXN]; 10 11 //stack<int>stk; 12 13 struct Edge { 14 int to, w, next; 15 } edge[MAXM]; 16 17 inline void init() { 18 // for(int i = 0; i <= n; i++ ) { 19 // first[i] = -1; 20 // } 21 memset(first, -1, sizeof(first)); 22 sign = 0; 23 } 24 25 inline void add_edge(int u, int v, int w) { 26 edge[sign].to = v; 27 edge[sign].w = w; 28 edge[sign].next = first[u]; 29 first[u] = sign++; 30 } 31 32 inline void init_tarjan() { 33 for(int i = 0; i <= n; i++ ) { 34 dfn[i] = low[i] = ins[i] = cut[i] = 0; 35 } 36 indx = scc = 0; 37 //while(!stk.empty()) { stk.pop(); } 38 } 39 40 void tarjan(int now, int faz) { 41 low[now] = dfn[now] = ++indx; 42 int child = 0; 43 for(int i = first[now]; ~i; i = edge[i].next) { 44 int to = edge[i].to; 45 if(!dfn[to]) { 46 tarjan(to, faz); 47 low[now] = min(low[now], low[to]); 48 ///非根节点,如果dfn[to] <= low[to]那么它是割点 49 if(low[to] >= dfn[now] && now != faz) { 50 cut[now] = 1; 51 } 52 if(now == faz) { 53 child++; 54 } 55 } 56 low[now] = min(low[now], dfn[to]); 57 } 58 if(child >= 2 && now == faz) { ///根节点有两个以上子树的是割点 59 cut[now] = 1; 60 } 61 } 62 63 int main() 64 { 65 //freopen("testdata.in", "r", stdin); 66 while(~scanf("%d %d", &n, &m)) { 67 init(); 68 init_tarjan(); 69 for(int i = 1; i <= m; i++ ) { 70 int u, v; 71 scanf("%d %d", &u, &v); 72 add_edge(u, v, 1); 73 add_edge(v, u, 1); 74 } 75 for(int i = 1; i <= n; i++ ) { 76 if(!dfn[i]) { 77 tarjan(i, i); 78 } 79 } 80 vector<int>vec; 81 for(int i = 1; i <= n; i++ ) { 82 if(cut[i]) { 83 vec.push_back(i); 84 } 85 } 86 printf("%d\n", vec.size()); 87 for(int i = 0; i < vec.size(); i++ ) { 88 printf("%d ", vec[i]); 89 } 90 } 91 return 0; 92 }