首页 > 代码库 > [HNOI2012]矿场搭建 题解

[HNOI2012]矿场搭建 题解

 [HNOI2012]矿场搭建

时间限制: 1 Sec  内存限制: 128 MB

题目描述

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

输入

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

输出

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

样例输入

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 

样例输出

Case 1: 2 4
Case 2: 4 1

提示

Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6)
  不知道有没有萌新和我一样,以为输出一个出去割点的联通块的个数和各个联通块的大小就完事了,事实证明,如果你A了超过1/3的点,算我输。
  事实上我们应当去对各个联通块进行分析,第一种,联通块在求的时候就没有碰到割点,那么它其实应该放两个安全出口,因为如果你放的那个刚好出了事故就没有别的安全出口了。第二种,只碰到了一个割点,那么就放一个出口就OK了。第三种,碰到了两个及两个以上的割点,那么我们就不用放了,无论那个割点出了事故我们都可以从别的地方走。
  至于方案数么,一个割点都没有的是size*(size-1)/2,注意特判size=1,有一个割点是size,有两个及两个以上割点无贡献。应该不用再分析了吧……
技术分享
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<map>
  7 #include<queue>
  8 #include<string>
  9 #include<cmath>
 10 using namespace std;
 11 struct ro{
 12     int to,next;
 13 }road[1500];
 14 int zz,a[1500];
 15 void build(int x,int y){
 16     zz++;
 17     road[zz].to=y;
 18     road[zz].next=a[x];
 19     a[x]=zz;
 20 }
 21 int v[1500],zz2,dfn[1500],low[1500];
 22 void tar(int x,int root){
 23     zz2++;
 24     v[x]=1;
 25     dfn[x]=low[x]=zz2;
 26     for(int i=a[x];i>0;i=road[i].next)
 27     {
 28         int y=road[i].to;
 29         if(!v[y])
 30         {
 31             tar(y,root);
 32             low[x]=min(low[x],low[y]);
 33             if(dfn[x]<=low[y])
 34             {
 35                 v[x]++ 36             }
 37         }
 38         else
 39         {
 40             low[x]=min(low[x],dfn[y]);
 41         }
 42     }
 43     if((x==root&&v[x]>2)||(x!=root&&v[x]>1))
 44         {
 45             v[x]=2;
 46         }
 47         else
 48             v[x]=1;
 49      
 50 }
 51 int m,top,st[1050],bj,jj,size,zzzz;
 52 bool rz[1050],rz2[1050];
 53 void work(int x){
 54     zz2++;
 55     dfn[x]=low[x]=zz2;
 56     rz[x]=rz2[x]=1;
 57     top++;
 58     st[top]=x;
 59     for(int i=a[x];i>0;i=road[i].next)
 60     {
 61         int y=road[i].to;
 62         if(v[y]==2)
 63         {
 64             if(!bj)
 65             {
 66                 bj=y;
 67                 jj=1;
 68             }
 69             else if(bj!=y) jj=2;
 70             continue; 
 71         }
 72         if(!rz2[y])
 73         {
 74             work(y);
 75             low[x]=min(low[x],low[y]);
 76         }
 77         else if(rz[y])
 78         {
 79             low[x]=min(low[x],dfn[y]);
 80         }
 81     }
 82     if(dfn[x]==low[x])
 83     {
 84         int v;
 85         zzzz++;
 86         do{
 87             v=st[top];
 88             top--;
 89             size++;
 90         }while(dfn[v]!=low[v]);
 91     }
 92 }
 93 int n;
 94 int main(){
 95 //  freopen("bzoj_2730.in","r",stdin);
 96 //  freopen("bzoj_2730.out","w",stdout);
 97     int js=0;
 98 while(~scanf("%d",&m))
 99 {
100     if(m==0) break;
101     js++;
102     zz=0;
103     memset(a,0,sizeof(a));
104     n=0;
105     for(int i=1;i<=m;i++)
106     {
107         int x,y;
108         scanf("%d%d",&x,&y);
109         build(x,y);
110         build(y,x);
111         n=max(n,max(x,y));
112     }
113     memset(v,0,sizeof(v));
114     memset(dfn,0,sizeof(dfn));
115     memset(low,0,sizeof(low));
116     zz2=0;
117     for(int i=1;i<=n;i++)
118     {
119         if(!v[i])
120         {
121             zz2=0;
122             tar(i,i);
123         }
124     }
125     memset(dfn,0,sizeof(dfn));
126     memset(low,0,sizeof(low));
127     zz2=0;
128     memset(rz,0,sizeof(rz));
129     memset(rz2,0,sizeof(rz2));
130     long long an=0,ans=1;
131     top=0;
132     memset(st,0,sizeof(st));
133     for(int i=1;i<=n;i++)
134     {
135         if(!rz2[i]&&v[i]!=2)
136         {
137             jj=0;
138             bj=0;
139             size=0;
140             work(i);
141             if(!jj)
142             {
143                 an+=2;
144                 if(size!=1) ans*=(size*(size-1))/2;
145             }
146             else if(jj==1)
147             {
148                 an++;
149                 ans*=size;
150             }
151         }
152     }
153     printf("Case %d: %lld %lld\n",js,an,ans);
154 }
155     //while(1);
156     return 0;
157 }
View Code

 

  

[HNOI2012]矿场搭建 题解