[BZOJ] 2730: [HNOI2012]矿场搭建

Posted Lev今天学习了吗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ] 2730: [HNOI2012]矿场搭建相关的知识,希望对你有一定的参考价值。

2730: [HNOI2012]矿场搭建

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2317  Solved: 1076
[Submit][Status][Discuss]

Description

煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

Input

输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖       S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。

Output

输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。

Sample Input

9
1 3
4 1
3 5
1 2
2 6
1 5
6 3
1 6
3 2
6
1 2
1 3
2 4
2 5
3 6
3 7
0

Sample Output

Case 1: 2 4
Case 2: 4 1

HINT

 

Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);

Case 2 的一组解为(4,5,6,7)。

 

Source

day1

Analysis

qwq调个水题调错了近十次,,,

那么我们根据数据可以建图,这个图我们可以得出这些性质:

1. 割点不是出口,如果割点是出口的话,塌掉好像,,,就塌掉了,不是最优解。正解应该是在点双连通分量里建一个出口。

2. 有两个割点的连通块就没必要建出口了:因为可以跑到两个割点相连接的其他连通块

3. 没有割点的连通块至少有两个出口:万一塌掉一个出口,,,,

第三点尤为重要。

那么解法就是:

首先求双连通分量顺便把割点数目计算出来

然后把每个连通块内建出口的方案乘起来

注意只有一个割点和无割点的情况才需要计算

还有一件事,n不是点的数量

还有一件事,初始化

还有一件事,需要输出 Case %d: 

Code

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<stack>
 5 #include<cstring>
 6 #define maxn 600
 7 using namespace std;
 8 
 9 int dfn[maxn],TIM,size[maxn],bcc_cnt,iscut[maxn],bccno[maxn],n,buck[maxn],m;
10 
11 struct edge{ int from; int u; int v; }e[maxn]; int tot,first[maxn];
12 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].u = u; e[tot].v = v; first[u] = tot; }
13 
14 vector<int> bcc[maxn];
15 stack<edge> S;
16 
17 int dfs(int u,int fa){
18     int lowu = dfn[u] = ++TIM;
19     int child = 0;
20     for(int i = first[u];i;i = e[i].from){
21         int v = e[i].v;
22         edge e = (edge){0,u,v};
23         if(!dfn[v]){
24             S.push(e);
25             child++;
26             int lowv = dfs(v,u);
27             lowu = min(lowu,lowv);
28             if(lowv >= dfn[u]){
29                 iscut[u] = true;
30                 bcc_cnt++; bcc[bcc_cnt].clear();
31                 for(;;){
32                     edge x = S.top();S.pop();
33                     if(bccno[x.u] != bcc_cnt){
34                         if(bccno[x.u]) buck[bccno[x.u]]++;
35                         bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt;
36                     }
37                     if(bccno[x.v] != bcc_cnt){
38                         if(bccno[x.v]) buck[bccno[x.v]]++;
39                         bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt;
40                     }
41                     if(x.u == u && x.v == v) break;
42                 }
43             }
44         }else if(dfn[v] < dfn[u] && v != fa) {
45             S.push(e); lowu = min(lowu,dfn[v]);
46         }
47     }if(fa < 0 && child == 1) iscut[u] = false;
48     return lowu;
49 }
50 
51 void Build(){
52     memset(dfn,0,sizeof(dfn));
53     memset(iscut,0,sizeof(iscut));
54     memset(bccno,0,sizeof(bccno));
55     memset(buck,0,sizeof(buck));
56     TIM = bcc_cnt = 0;
57     
58     for(int i = 1;i <= n;i++)
59         if(!dfn[i]) dfs(i,-1);
60 }
61 
62 int main(){
63     int T = 1;
64     scanf("%d",&m);
65     while(m){
66         n = 0;
67         for(int i = 1;i <= m;i++){
68             int x,y; scanf("%d%d",&x,&y);
69             n = max(n,max(x,y));
70             insert(x,y); insert(y,x);
71         }Build();
72         for(int i = 1;i <= n;i++)
73             if(iscut[i]) buck[bccno[i]]++;
74             
75         long long ans = 1;
76         int tot = 0;
77         for(int i = 1;i <= bcc_cnt;i++){
78             if(buck[i] == 1) ans *= max(((int)bcc[i].size()-1),1),tot++;
79             if(!buck[i]) ans *= bcc[i].size()*(bcc[i].size()-1)/2,tot += 2;
80 //            cout << "ans" << ans << endl;
81         }
82         printf("Case %d: %d %lld\n",T,tot,ans); T++;
83 //        cout << ans << endl;
84 //        cout << "buck: ";
85 //        for(int i = 1;i <= n;i++) printf("%d ",buck[i]); cout << endl;
86 //        cout << "bcc: ";
87 //        for(int i = 1;i <= bcc_cnt;i++) printf("%d ",bcc[i].size()); cout << endl;
88         memset(first,0,sizeof(first));
89         tot = 0;
90         scanf("%d",&m);
91     }return 0;
92 }
qwq

 

 

以上是关于[BZOJ] 2730: [HNOI2012]矿场搭建的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 2730][HNOI 2012] 矿场搭建

bzoj 2730: [HNOI2012]矿场搭建

BZOJ 2730:[HNOI2012]矿场搭建(割点+连通块)

bzoj2730 HNOI2012—矿场搭建

BZOJ 2730 [HNOI2012]矿场搭建

BZOJ2730: [HNOI2012]矿场搭建