POJ 3177 Redundant Paths(边双连通分量)
题目大意
给了一个有 n(1<=n<=5000) 个点 m(n-1<=m<=10000) 个边的连通的无向图,现在问最少需要添加多少条边才能使得整个图中所有的点对之间至少存在两条没有交集的路径?
有一个坑就是,给的无向图中有可能有重边,但是重边的话只能算一条边
做法分析
根据题意可以知道,这题要求一个边双连通分量,求出边双连通分量之后,得到一棵树,找出所有书中度为 1 的点的个数 num,我们添加边肯定是在度为 1 的点之间添加,那么,最少要添加的边的数量不难想到是:(num+1)/2
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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=5006; 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 }
AC通道