http://poj.org/problem?id=3352
题意:给出一个有n个顶点m条边的无向连通图,问至少添加几条边,使删除任意一条边原图仍连通。
思路:一个边双连通图删除任意一条边仍为连通图。故此题即为求原图添加几条边能成为边双连通图。先对无向图中的强连通分量进行缩点,所有的缩点就能构成一棵树,节点之间的连线即为桥。只需将树中的叶子节点相连,就能构成一个边双连通图。叶子节点即为度为1的连通分量。low[i]值相同的点在同一个连通分量中。所加边数=(叶子数+1)/2;
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 7 const int N=1010; 8 struct node 9 { 10 int u,v; 11 int next; 12 } edge[N*2]; 13 int n,m,cnt,dfs_clock; 14 int head[N],degree[N]; 15 int low[N],dfn[N],vis[N]; 16 void init() 17 { 18 cnt = 0; 19 dfs_clock = 0; 20 memset(head,-1,sizeof(head)); 21 memset(vis,0,sizeof(vis)); 22 memset(low,0,sizeof(low)); 23 memset(dfn,0,sizeof(dfn)); 24 memset(degree,0,sizeof(degree)); 25 } 26 void add(int u,int v) 27 { 28 edge[cnt].u = u; 29 edge[cnt].v = v; 30 edge[cnt].next = head[u]; 31 head[u] = cnt++; 32 } 33 void dfs(int u,int father)//简化的无向图Tarjan算法 34 { 35 vis[u] = 1; 36 low[u]=dfn[u]=++dfs_clock; 37 for (int i = head[u]; i!=-1; i=edge[i].next) 38 { 39 int v = edge[i].v; 40 if (vis[v]==1&&father!=v) 41 { 42 low[u] = min(low[u],dfn[v]); 43 } 44 if (vis[v]==0) 45 { 46 dfs(v,u); 47 low[u] = min(low[u],low[v]); 48 } 49 } 50 vis[u] = 2; 51 } 52 int main() 53 { 54 while(~scanf("%d%d",&n,&m)) 55 { 56 int u,v; 57 init(); 58 for (int i = 0; i < m; i++) 59 { 60 scanf("%d%d",&u,&v); 61 add(u,v); 62 add(v,u); 63 } 64 dfs(1,1);//原图是连通的故只需从一个点就能遍历全图 65 for (int u = 1; u <= n; u++) 66 { 67 for (int j = head[u]; j!=-1; j=edge[j].next) 68 { 69 int v = edge[j].v; 70 if (low[u]!=low[v])//点u与点v相连但是不在同一个连通分量中 71 { 72 degree[low[u]]++;//点u所在的连通分量的度+1 73 } 74 } 75 } 76 int leaf = 0; 77 for (int u = 0; u <= n; u++) 78 { 79 if (degree[u]==1) 80 leaf++;//求叶子节点 81 } 82 int ans = (leaf+1)/2; 83 printf("%d ",ans); 84 } 85 return 0; 86 }