Road Construction(无向图的双连通分量)

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\n",ans);
84     }
85     return 0;
86 }
View Code

 

posted @ 2014-02-16 21:07  N_ll  阅读(501)  评论(0编辑  收藏  举报