[HNOI2012]矿场搭建

                                                   [HNOI2012]矿场搭建

 

【题目描述】

 

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

 

【输入格式】

 

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

 

【输出格式】

 

输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,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);

 

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

 

比较明显的tarjan求割点

一开始我想错了 以为挖煤点随便塌,数量不限。。

回到正题,既然是要在任意一个挖煤点塌了之后可以跑到救援点 

那这救援点一定不能放在割点上 要不你就哭去吧

那就显然求出所有割点 再求其他连通块

显然有这样的结论:

1丶全图无割点 只有一个连通块 那就随意放两个救援点

因为万一塌了一个救援点 你还有另一个嘛 方案数C(n,2);

2丶一个连通块连着一个割点,在连通块中放一个救援点 

此连通块中的任意一个点都可以放,根据乘法原理方案数=原方案数*连通块的点数

3丶一个连通块连着两个或以上的割点 那就不用安放救援点 

因为路有多条 塌了一个割点 还有其他路可走

 

  1 #include <cctype>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 typedef long long LL;
  6 
  7 const int MAXN=20010;
  8 
  9 int m,n,id,top,inr,opt,cnt;
 10 
 11 int dfn[MAXN],low[MAXN],stack[MAXN],cut[MAXN],belong[MAXN],siz[MAXN],c[MAXN];
 12 
 13 bool vis[MAXN];
 14 
 15 LL ans;
 16 
 17 struct node {
 18     int to;
 19     int next;
 20     node(){}
 21     node(int to,int next):to(to),next(next){}
 22 };
 23 node e[MAXN];
 24 
 25 int head[MAXN],tot;
 26 
 27 inline void read(int&x) {
 28     int f=1;register char c=getchar();
 29     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
 30     for(;isdigit(c);x=x*10+c-48,c=getchar());
 31     x=x*f;
 32 }
 33 
 34 inline void clear() {
 35     tot=0;top=0;inr=0;id=0;cnt=0;ans=1;n=0;
 36     memset(c,0,sizeof c);
 37     memset(dfn,0,sizeof dfn);
 38     memset(vis,0,sizeof vis);
 39     memset(low,0,sizeof low);
 40     memset(cut,0,sizeof cut);
 41     memset(siz,0,sizeof siz);
 42     memset(head,-1,sizeof head);
 43     memset(belong,0,sizeof belong);
 44 }
 45 
 46 struct RUNNING {
 47     int min(int a,int b) {return a<b?a:b;}
 48     
 49     void add(int x,int y) {
 50         e[++tot]=node(y,head[x]);
 51         head[x]=tot;
 52         e[++tot]=node(x,head[y]);
 53         head[y]=tot;
 54     }
 55     
 56     void tarjan(int u,int fa) {
 57         dfn[u]=low[u]=++inr;
 58         stack[++top]=u;
 59         vis[u]=true;
 60         int x=0;
 61         for(int i=head[u];i!=-1;i=e[i].next) {
 62             int v=e[i].to;
 63             if(v==fa) continue;
 64             if(!dfn[v]) {
 65                 ++x;
 66                 tarjan(v,u);
 67                 low[u]=min(low[u],low[v]);
 68                 if(dfn[u]<=low[v]) cut[u]=1;
 69             }
 70             else if(vis[v]) low[u]=min(low[u],dfn[v]);
 71         }
 72         if(fa==-1&&x<=1) cut[u]=0;
 73     }
 74     
 75     void Dfs(int u) {
 76         vis[u]=true;++siz[id];
 77         for(int i=head[u];i!=-1;i=e[i].next) {
 78             int v=e[i].to;
 79             if(vis[v]) continue;
 80             if(!cut[v]) Dfs(v);
 81             else if(belong[v]!=id) {
 82                 belong[v]=id;
 83                 ++c[id];
 84             }
 85         }
 86     }
 87     
 88 } yf;
 89 
 90 int hh() {
 91     freopen("bzoj_2730.in","r",stdin);
 92     freopen("bzoj_2730.out","w",stdout);
 93     while(true) {
 94         read(m);
 95         if(!m) break;
 96         clear();
 97         for(int x,y;m--;) {
 98             read(x);read(y);
 99             yf.add(x,y);
100             if(x>n) n=x;
101             if(y>n) n=y;
102         }
103         for(int i=1;i<=n;++i)
104           if(!dfn[i]) yf.tarjan(i,-1);
105         memset(vis,false,sizeof vis);
106         for(int i=1;i<=n;++i) 
107           if(!cut[i]&&!vis[i]) ++id,yf.Dfs(i);
108         if(id==1) cnt=2,ans=(LL)n*(n-1)/2;
109         else {
110             for(int i=1;i<=id;++i)
111               if(c[i]==1) ++cnt,ans=(LL)ans*siz[i];
112         }
113         printf("Case %d: %d %lld\n",++opt,cnt,ans);
114     }
115     return 0;
116 }
117 
118 int sb=hh();
119 int main(int argc,char**argv) {;}
代码

 

posted @ 2017-09-04 21:49  拿叉插猹哈  阅读(139)  评论(0编辑  收藏  举报