[BZOJ] 2730: [HNOI2012]矿场搭建
Posted Lev今天学习了吗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ] 2730: [HNOI2012]矿场搭建相关的知识,希望对你有一定的参考价值。
2730: [HNOI2012]矿场搭建
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
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 2: 4 1
HINT
Source
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 }
以上是关于[BZOJ] 2730: [HNOI2012]矿场搭建的主要内容,如果未能解决你的问题,请参考以下文章