BZOJ 2730 HNOI2012 矿场搭建

2730: [HNOI2012]矿场搭建

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2458  Solved: 1147
[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

由于数据范围小,此题可以暴力。。。

显然若非割点坍塌,就无所谓啦,只要考虑坍塌在割点的情况

删去所有割点得到若干连通块,如果图中只有一个连通块,一共只需要设两个

若一个连通块可以到达两个割点的话则不用设置救援出口,否则要设置一个

割点可以删去点然后遍历图求,复杂度n方

对每个割点划分的各个连通块染色,重复染色记为-1

其实可以tarjin求割点,我太懒了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;int f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=1e3+10;
struct node{
    int y,next;
}e[MAXN];
int linkk[MAXN],len,n,m,T,f[MAXN],id[MAXN],vis[MAXN],cnt[MAXN];
inline void insert(int xx,int yy){
    e[++len].y=yy;e[len].next=linkk[xx];linkk[xx]=len;
}
inline void dfs1(int st,int fa){
    vis[st]=1;
    for(int i=linkk[st];i;i=e[i].next){
        if(!vis[e[i].y]&&e[i].y!=fa){
            dfs1(e[i].y,fa);
        }
    }
}
inline void dfs2(int st,int fa){
    if(id[st]==0) id[st]=fa;
    else id[st]=-1;
    vis[st]=1;
    for(int i=linkk[st];i;i=e[i].next){
        if(!vis[e[i].y]&&!cnt[e[i].y]){
            dfs2(e[i].y,fa);
        }
    }
}
int main(){
    //freopen("All.in","r",stdin);
    //freopen("zh.out","w",stdout);
    while(1){
        m=read();
        if(m==0) return 0;
        T++;
        printf("Case %d: ",T);
        memset(linkk,0,sizeof(linkk));
        memset(e,0,sizeof(e));
        memset(f,0,sizeof(f));
        memset(vis,0,sizeof(vis));
        memset(id,0,sizeof(id));
        memset(cnt,0,sizeof(cnt));
        len=0;n=0;
        for(int i=1;i<=m;i++){
            int xx=read();int yy=read();
            insert(xx,yy);insert(yy,xx);
            n=max(max(xx,yy),n);
        }
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            dfs1((i%n+1),i);
            for(int j=1;j<=n;j++){
                if(!vis[j]&&i!=j) {
                    cnt[i]=1;
                    break;
                }
            }
        }
        int k=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            if(cnt[i]){
                memset(vis,0,sizeof(vis));
                for(int j=linkk[i];j;j=e[j].next){
                    if(!vis[e[j].y]&&!cnt[e[j].y]){
                        dfs2(e[j].y,++k);
                    }
                }
            }
        }
        int tot=0;ll ans=1;
        for(int i=1;i<=n;i++){
            if(id[i]!=-1) f[id[i]]++;
        }
        for(int i=1;i<=k;i++){
            if(f[i]!=0) tot++,ans*=f[i];
        }
        if(!tot) printf("2 %d\n",(n-1)*n/2);
        else printf("%d %lld\n",tot,ans);
    } 
    return 0;
}

  

 

posted @ 2017-12-18 10:04  zhangenming  阅读(154)  评论(0编辑  收藏  举报