题目链接:
题目描述:
给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥?
解题思路:
先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条边两个端点根节点的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 }