题目大意
给一个 n 个点 m 条边的无向图,要求在删掉任意一条边之后,图中所有的节点保持连通性,问至少需要添加多少条边?
做法分析
求出边双连通分量,缩点之后,找出树中度为 1 的点的个数 num,添加边肯定是在度为 1 的顶点上添加,这样至少添加的边的个数就为 (num+1)/2;
参考代码
POJ 3352
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <stack> 6 #include <algorithm> 7 8 using namespace std; 9 10 const int N=1006; 11 12 vector <int> arc[N]; 13 int dfn[N], low[N], id[N]; 14 bool vs[N]; 15 stack <int> s; 16 int n, m, ind, T; 17 18 void tarjan(int u, int pre) 19 { 20 dfn[u]=low[u]=T++; 21 s.push(u), vs[u]=1; 22 int len=(int)arc[u].size(), last=-1; 23 for(int i=0; i<len; i++) 24 { 25 int v=arc[u][i]; 26 if(pre==v || v==last) continue; 27 last=v; 28 if(dfn[v]==-1) 29 { 30 tarjan(v, u); 31 if(low[u]>low[v]) low[u]=low[v]; 32 } 33 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 34 } 35 if(low[u]==dfn[u]) 36 { 37 for(int v; 1; ) 38 { 39 v=s.top(); 40 vs[v]=0, s.pop(); 41 id[v]=ind; 42 if(v==u) break; 43 } 44 ind++; 45 } 46 } 47 48 int main() 49 { 50 scanf("%d%d", &n, &m); 51 for(int i=1; i<=n; i++) arc[i].clear(); 52 for(int i=0, a, b; i<m; i++) 53 { 54 scanf("%d%d", &a, &b); 55 arc[a].push_back(b); 56 arc[b].push_back(a); 57 } 58 for(int i=1; i<=n; i++) sort(arc[i].begin(), arc[i].end()); 59 for(int i=1; i<=n; i++) dfn[i]=-1, vs[i]=0; 60 while(!s.empty()) s.pop(); 61 ind=T=0; 62 for(int i=1; i<=n; i++) if(dfn[i]==-1) tarjan(i, -1); 63 for(int i=0; i<ind; i++) dfn[i]=0; 64 for(int i=1; i<=n; i++) 65 { 66 int u=id[i], len=(int)arc[i].size(), last=-1; 67 for(int j=0; j<len; j++) 68 { 69 if(arc[i][j]==last) continue; 70 last=arc[i][j]; 71 int v=id[arc[i][j]]; 72 if(u!=v) dfn[u]++, dfn[v]++; 73 } 74 } 75 int cnt=0; 76 for(int i=0; i<ind; i++) if(dfn[i]==2) cnt++; 77 printf("%d\n", (cnt+1)/2); 78 return 0; 79 }