Poj 3177 Redundant Paths (双连通分支+节点统计)

题目描述:

  给出一个无向的连通图,问最少加入几条边,才能使所给的图变为无桥的双连通图?

解题思路:

  可以求出原图中所有的不包含桥的所有最大连通子图,然后对连通子图进行标记缩点,统计度为1的叶子节点leaf有多少个,答案就是(leaf+1)/2;

  这个题目有重边,在处理的时候要注意下。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 5005;
 8 struct node
 9 {
10     int to, next;
11 } edge[maxn*2];
12 
13 int low[maxn], dfn[maxn], head[maxn], id[maxn], in[maxn];
14 int stack[maxn], tot, ntime, cnt, top, In;
15 void init ()
16 {
17     tot = ntime = cnt = top = In = 0;
18     memset (in, 0, sizeof(in));
19     memset (id, 0, sizeof(id));
20     memset (low, 0, sizeof(low));
21     memset (dfn, 0, sizeof(dfn));
22     memset (head, -1, sizeof(head));
23     memset (stack, 0, sizeof(stack));
24 }
25 void Add (int from, int to)
26 {
27     edge[tot].to = to;
28     edge[tot].next = head[from];
29     head[from] = tot++;
30 }
31 void Tarjan (int u, int father)
32 {
33     int k = 0;
34     low[u] = dfn[u] = ++ntime;
35     stack[top++] = u;
36     for (int i=head[u]; i!=-1; i=edge[i].next)
37     {
38         int v = edge[i].to;
39         if (v==father && !k)
40            {//判定重边
41                 k++;
42                 continue;
43            }
44         if (!dfn[v])
45         {
46             Tarjan (v, u);
47             low[u] = min (low[v], low[u]);
48         }
49         else
50             low[u] = min (low[u], dfn[v]);
51     }
52     if (low[u] == dfn[u])
53     {
54         cnt ++;
55         while (1)
56         {//对同一个连通块内的点染色
57             int v = stack[--top];
58             id[v] = cnt;
59             if (v == u)
60                 break;
61         }
62     }
63 }
64 int main ()
65 {
66     int n, m;
67     while (scanf ("%d %d", &n, &m) != EOF)
68     {
69         init ();
70         while (m --)
71         {
72             int u, v;
73             scanf ("%d %d", &u, &v);
74             Add (u, v);
75             Add (v, u);
76         }
77         for (int i=1; i<=n; i++)
78             if (!dfn[i])
79                 Tarjan (i, 0);
80         for (int i=1; i<=n; i++)
81             for (int j=head[i]; j!=-1; j=edge[j].next)
82             {
83                 int u = id[i];
84                 int v = id[edge[j].to];
85                 if (v != u)
86                 {//统计缩点后的图中每个点的度
87                     in[v] ++;
88                     in[u] ++;
89                 }
90             }
91         for (int i=1; i<=cnt; i++)
92             if (in[i] == 2)//因为是无向图建图方式的原因,当度为2的时候才是叶子节点
93                 In ++;
94         printf ("%d\n", (In+1)/2);
95     }
96     return 0;
97 }

 

posted @ 2015-07-22 20:45  罗茜  阅读(196)  评论(0编辑  收藏  举报