Poj 3694 Network (连通图缩点+LCA+并查集)

题目链接:

  Poj 3694 Network

题目描述:

  给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥?

解题思路:

  先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条边两个端点根节点的LCA,统计其中的桥,然后把这个环中的节点加到一个集合中,根节点标记为LCA。

题目不难,坑在了数组初始化和大小

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 const int maxn = 100005;
  8 struct node
  9 {
 10     int to, next;
 11 } edge[4*maxn], Edge[2*maxn];
 12 int head[maxn], low[maxn], dfn[maxn], id[maxn], Head[maxn], Father[maxn];
 13 int pre[maxn], deep[maxn], stack[maxn], tot, ntime, top, cnt, Tot;
 14 
 15 void init ()
 16 {
 17     Tot = tot = ntime = top = cnt = 0;
 18     memset (id, 0, sizeof(id));
 19     memset (low, 0, sizeof(low));
 20     memset (dfn, 0, sizeof(dfn));
 21     memset (pre, 0, sizeof(pre));
 22     memset (head, -1, sizeof(head));
 23     memset (deep, 0, sizeof(deep));
 24     memset (Head, -1, sizeof(Head));
 25 }
 26 void Add (int from, int to)
 27 {
 28     Edge[Tot].to = to;
 29     Edge[Tot].next = Head[from];
 30     Head[from] = Tot++;
 31 }
 32 void add (int from, int to)
 33 {
 34     edge[tot].to = to;
 35     edge[tot].next = head[from];
 36     head[from] = tot++;
 37 }
 38 int find (int x)
 39 {
 40     if (x != Father[x])
 41         Father[x] = find(Father[x]);
 42     return Father[x];
 43 }
 44 void dfs (int u, int father, int d)
 45 {
 46     pre[u] = father;
 47     deep[u] = d;
 48     for (int i=Head[u]; i!=-1; i=Edge[i].next)
 49     {
 50         int v = Edge[i].to;
 51         if (father != v)
 52             dfs (v, u, d+1);
 53     }
 54 }
 55 int LCA (int a, int b)
 56 {
 57     while (a != b)
 58     {
 59         if (deep[a] > deep[b])
 60             a = pre[a];
 61         else if (deep[a] < deep[b])
 62             b = pre[b];
 63         else
 64         {
 65             a = pre[a];
 66             b = pre[b];
 67         }
 68         a = find (a);
 69         b = find (b);
 70     }
 71     return a;
 72 }
 73 void Tarjan (int u, int father)
 74 {
 75     int k = 0;
 76     low[u] = dfn[u] = ++ ntime;
 77     stack[top ++] = u;
 78     for (int i=head[u]; i!=-1; i=edge[i].next)
 79     {
 80         int v = edge[i].to;
 81         if (father == v && !k)
 82         {
 83             k ++;
 84             continue;
 85         }
 86         if (!dfn[v])
 87         {
 88             Tarjan (v, u);
 89             low[u] = min (low[u], low[v]);
 90         }
 91         else
 92             low[u] = min (low[u], dfn[v]);
 93     }
 94     if (low[u] == dfn[u])
 95     {
 96         cnt ++;
 97         while (1)
 98         {
 99             int v = stack[--top];
100             id[v] = cnt;
101             if (v == u)
102                 break;
103         }
104     }
105 }
106 void solve (int n)
107 {
108     Tarjan (1, 0);
109     for (int i=1; i<=n; i++)
110         for (int j=head[i]; j!=-1; j=edge[j].next)
111         {
112             int u = id[i];
113             int v = id[edge[j].to];
114             if (u != v)
115                 Add (u, v);
116         }
117     dfs (1, 0, 0);
118     
119     for (int i=0; i<=cnt; i++)
120         Father[i] = i;
121     int q;
122     cnt --;
123     scanf ("%d", &q);
124     while (q --)
125     {
126         int u, v;
127         scanf ("%d %d", &u, &v);
128         u = find(id[u]);
129         v = find(id[v]);
130         int lca = LCA(u, v);
131         while (u != lca)
132         {
133             cnt --;
134             Father[u] = lca;
135             u = find (pre[u]);
136         }
137         while (v !=lca)
138         {
139             cnt --;
140             Father[v] = lca;
141             v = find (pre[v]);
142         }
143         printf ("%d\n", cnt);
144     }
145 }
146 int main ()
147 {
148     int n, m, l = 0;
149     while (scanf ("%d %d",&n, &m), n + m)
150     {
151         init ();
152         while (m --)
153         {
154             int u, v;
155             scanf ("%d %d", &u, &v);
156             add (u, v);
157             add (v, u);
158         }
159         printf ("Case %d:\n", ++l);
160         solve (n);
161         printf ("\n");
162     }
163     return 0;
164 }

 

转载于:https://www.cnblogs.com/alihenaixiao/p/4674248.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值