標籤:
題目連結
題意:n條隧道由一些點串連而成,其中每條隧道連結兩個連接點。任意兩個連接點之間最多隻有一條隧道。任務就是在這些連接點中,安裝盡量少的太平井和逃生裝置,使得不管哪個連接點倒塌,工人都能從其他太平井逃脫,求最少安裝數量和方案。
分析:本題相當於在一張無向圖上選擇盡量少的點塗黑(對應太平井),使任意一個點被刪除後,每個連通分量都至少還有一個黑點。不同的連通分量最多有一個公用點即割點,將割點塗上是不划算的,因為刪除割點後,要保證每個連通分量還要有黑點,所以還要在其他的連通分量中塗黑點,如果不塗割點,還能省一個呢,在一個點連通分量中塗兩個黑點也是不划算的, 所以只有當一個點連通分量中含有一個割點,那麼就塗 除了 割點 其他的點,因為,如果刪除這個割點後,你得保證剩下的有一個黑點。 對於一個連通分量中含有 >= 2個割點,就不用塗了,因為他有兩個割點不會全部刪除,可以通向其他的連通分量的 太平井,
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <vector> 6 #include <stack> 7 using namespace std; 8 typedef long long LL; 9 const int Max = 50005; 10 struct Edge 11 { 12 int u, v; 13 }; 14 vector<int> G[Max], bcc[Max]; 15 int pre[Max], bccno[Max], iscut[Max]; 16 int dfs_clock, bcc_cnt; 17 stack<Edge> S; 18 int dfs(int u, int fa) 19 { 20 int lowu = pre[u] = ++dfs_clock; 21 int Size = G[u].size(); 22 int child = 0; 23 for (int i = 0; i < Size; i++) 24 { 25 int v = G[u][i]; 26 Edge e; 27 e.u = u; 28 e.v = v; 29 if (!pre[v]) 30 { 31 S.push(e); 32 child++; 33 int lowv = dfs(v, u); 34 lowu = min(lowu, lowv); 35 if (lowv >= pre[u]) 36 { 37 iscut[u] = true; 38 bcc_cnt++; 39 bcc[bcc_cnt].clear(); 40 for (; ;) 41 { 42 Edge x = S.top(); 43 S.pop(); 44 if (bccno[x.u] != bcc_cnt) 45 { 46 bccno[x.u] = bcc_cnt; 47 bcc[bcc_cnt].push_back(x.u); 48 } 49 if (bccno[x.v] != bcc_cnt) 50 { 51 bccno[x.v] = bcc_cnt; 52 bcc[bcc_cnt].push_back(x.v); 53 } 54 if (x.u == u && x.v == v) 55 break; 56 } 57 } 58 } 59 else if (pre[v] < pre[u] && v != fa) 60 lowu = min(lowu, pre[v]); 61 } 62 if (child == 1 && fa < 0) 63 iscut[u] = 0; 64 return lowu; 65 } 66 void find_bcc(int n) 67 { 68 if (!S.empty()) 69 S.pop(); 70 memset(pre, 0, sizeof(pre)); 71 memset(bccno, 0, sizeof(bccno)); 72 memset(iscut, 0, sizeof(iscut)); 73 dfs_clock = bcc_cnt = 0; 74 for (int i = 1; i <= n; i++) 75 { 76 if (!pre[i]) 77 dfs(i, -1); 78 } 79 } 80 int main() 81 { 82 int test = 0, n; 83 while (scanf("%d", &n) != EOF && n) 84 { 85 int u, v, temp = -1; 86 for (int i = 1; i < Max; i++) 87 G[i].clear(); //清空 88 for (int i = 1; i <= n; i++) 89 { 90 scanf("%d%d", &u, &v); 91 G[u].push_back(v); 92 G[v].push_back(u); 93 temp = max(temp, max(u, v)); // 找到最大的點 94 } 95 find_bcc(temp); // 找連通分量 96 LL ans1 = 0, ans2 = 1; 97 for (int i = 1; i <= bcc_cnt; i++) 98 { 99 int cut_cnt = 0;100 int Size = bcc[i].size();101 for (int j = 0; j < Size; j++)102 {103 if (iscut[ bcc[i][j] ])104 cut_cnt++;105 }106 if (cut_cnt == 1)107 {108 ans1++;109 ans2 *= (LL)(Size - 1);110 }111 }112 if (bcc_cnt == 1)113 {114 ans1 = 2;115 ans2 = (LL) bcc[1].size() * (LL) (bcc[1].size() - 1) / 2;116 }117 printf("Case %d: %lld %lld\n", ++test, ans1, ans2);118 }119 return 0;120 }
View Code
UVA5135 Mining Your Own Business ( 無向圖雙連通分量)