zoukankan      html  css  js  c++  java
  • [BZOJ 2730][HNOI 2012] 矿场搭建

    2730: [HNOI2012]矿场搭建

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2113  Solved: 979
    [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)。

    题意

    给定一个无向图, 分配最少的救援通道使任意一个结点断开后所有其余结点都与至少一个救援通道连通.

    题解

    断开一个点还能保持连通...除了点双联通分量还有谁? 

    每个点双连通分量里都至少要有一个并且为了保证最少只能有一个. 由于每个双联通分量中任选一个安置救援通道即可, 所以最终的方案数为各双联通分量的大小之积.

    $Tarjan$ 求割顶然后乱搞也可以过.

    参考代码

    GitHub

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 
      5 const int MAXN=505;
      6 typedef long long LL;
      7 
      8 struct Edge{
      9     int to;
     10     Edge* next;
     11 };
     12 Edge E[MAXN];
     13 Edge* head[MAXN];
     14 Edge* top=E;
     15 
     16 int n,m,len,rt,son,ans,cnt,tot,Node,Case=0,Time,dfn[MAXN],low[MAXN],vis[MAXN];
     17 LL f;
     18 
     19 bool exist[MAXN],Gd[MAXN];
     20 
     21 void DFS(int);
     22 void Tarjan(int);
     23 void Initialize();
     24 void Insert(int,int);
     25 int main()
     26 {
     27     while(scanf("%d",&m)==1){
     28         if(m==0)
     29             break;
     30         Initialize();
     31         for(int i=1;i<=m;i++){
     32             if(exist[i] && !dfn[i]){
     33                 rt=i;
     34                 son=0;
     35                 Tarjan(i);
     36                 if(son>1 && !Gd[i])
     37                     Gd[i]=true;
     38             }
     39         }
     40         for(int i=1;i<=m+1;i++){
     41             if(!exist[i])
     42                 continue;
     43             if(!Gd[i]){
     44                 cnt=0;
     45                 Node=1;
     46                 tot++;
     47                 DFS(i);
     48                 if(!cnt){
     49                     ans+=2;
     50                     f=f*Node*1ll*(Node-1)/2;
     51                 }
     52                 else if(cnt==1){
     53                     ans++;
     54                     f=Node*1ll*f;
     55                 }
     56             }
     57         }
     58         printf("Case %d: %d %lld
    ",Case,ans,f);
     59     }
     60     return 0;
     61 }
     62 
     63 void Initialize(){
     64     int x,y;
     65     memset(head,0,sizeof head);
     66     memset(exist,0,sizeof exist);
     67     memset(dfn,0,sizeof dfn);
     68     memset(low,0,sizeof low);
     69     memset(Gd,0,sizeof Gd);
     70     n=0;
     71     len=0;
     72     Time=0;
     73     rt=-1;
     74     f=1ll;
     75     ans=0;
     76     Case++;
     77 
     78     for(int i=1;i<=m;i++){
     79         scanf("%d%d",&x,&y);
     80         if(!exist[x]){
     81             exist[x]=1;
     82             n++;
     83         }
     84         if(!exist[y]){
     85             exist[y]=1;
     86             n++;
     87         }
     88         Insert(x,y);
     89         Insert(y,x);
     90     }
     91 }
     92 
     93 void DFS(int x){
     94     exist[x]=false;
     95     for(Edge* i=head[x];i!=NULL;i=i->next){
     96         if(!exist[i->to])
     97             continue;
     98         if(Gd[i->to] && vis[i->to]!=tot){
     99             vis[i->to]=tot;
    100             cnt++;
    101         }
    102         else if(!Gd[i->to]){
    103             Node++;
    104             DFS(i->to);
    105         }
    106     }
    107 }
    108 
    109 void Tarjan(int x){
    110     low[x]=dfn[x]=++Time;
    111     for(Edge* i=head[x];i!=NULL;i=i->next){
    112         if(!dfn[i->to]){
    113             Tarjan(i->to);
    114             if(x==rt)
    115                 son++;
    116             else{
    117                 low[x]=std::min(low[x],low[i->to]);
    118                 if(low[i->to]>=dfn[x] && !Gd[x])
    119                     Gd[x]=true;    
    120             }
    121         }
    122         else low[x]=std::min(low[x],dfn[i->to]);
    123     }
    124 }
    125 
    126 void Insert(int from,int to){
    127     top->to=to;
    128     top->next=head[from];
    129     head[from]=top;
    130     top++;
    131 }
    Backup

  • 相关阅读:
    Java-注解(@Annotation)
    面试(三)---volatile
    面试(二)---synchronized
    Linux使用技巧(一):vim中选中多行、复制和粘贴
    Git——学习Git
    【Linux】Linux下cp ~中关于“~”的疑问
    【Linux】Linux中cd test和cd /test以及类似命令的区别
    【Linux】Linux系统中/opt 和 /usr目录
    【Linux】Linux的文件权限
    读《大数据时代下半场-数据治理、驱动与变现》--1
  • 原文地址:https://www.cnblogs.com/rvalue/p/7341421.html
Copyright © 2011-2022 走看看