• BZOJ2730: [HNOI2012]矿场搭建


    BZOJ2730: [HNOI2012]矿场搭建

    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)。
    题解Here!

    思路:找出割点和所有的双连通分量,然后统计每个双连通分量里的个点的个数分情况讨论。

    1. 若该连通分量里有不少于两个割点,则它是安全的,因为无论哪个割点炸了,里面的点可以通过其他的没炸的割点跑到其他的双连通分量里去。

    2. 若该连通分量里只有一个割点,那么如果这个割点炸了,则里面的点就不可能跑到其他的双连通分量里去了,所以要在这个割点里建一个出口。

    3. 若该连通分量里一个割点也没有,说明它与外界完全不连通,这时如果只建一个出口的话,那么如果这个出口炸了就 GG ,所以还需要另一个出口“以防万一”(即建两个出口)

    对于方案数的话,我们发现如果要建出口的话,该双连通分量里的任何一个非割点的节点都是可以的,因此用一下组合数学就可以搞定了。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define MAXN 510
    using namespace std;
    int n,m,c,d,num,times,size;
    long long ans,sum;
    int head[MAXN],deep[MAXN],low[MAXN],fa[MAXN],vis[MAXN];
    bool flag[MAXN];
    struct Graph{
        int next,to;
    }a[MAXN<<1];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    inline void add(int x,int y){
        a[c].to=y;a[c].next=head[x];head[x]=c++;
        a[c].to=x;a[c].next=head[y];head[y]=c++;
    }
    void dfs(int x){
        int s=0;
        deep[x]=low[x]=d++;
        for(int i=head[x];i;i=a[i].next){
            int v=a[i].to;
            if(!deep[v]){
                fa[v]=fa[x];
                dfs(v);
                low[x]=min(low[x],low[v]);
                if(low[v]>=deep[x]&&x!=fa[x])flag[x]=true;
                if(x==fa[x])s++;
            }
            low[x]=min(low[x],deep[v]);
        }
        if(x==fa[x]&&s>=2)flag[fa[x]]=true;
    }
    void answer(int x){
        size++;
        vis[x]=times;
        for(int i=head[x];i;i=a[i].next){
            int v=a[i].to;
            if(vis[v]!=times&&flag[v]){
                num++;
                vis[v]=times;
            }
            if(!vis[v]&&!flag[v])answer(v);
        }
    }
    void work(){
        for(int i=1;i<=n;i++)
        if(!vis[i]&&!flag[i]){
            size=num=0;
            times++;
            answer(i);
            if(num==0){ans+=2;sum*=size*(size-1)/2;}
            if(num==1){ans++;sum*=size;}
        }
        printf("%lld %lld
    ",ans,sum);
    }
    void init(){
        c=d=sum=1;
        n=times=ans=0;
        memset(head,0,sizeof(head));
        memset(deep,0,sizeof(deep));
        memset(low,0,sizeof(low));
        memset(flag,false,sizeof(flag));
        memset(vis,0,sizeof(vis));
        int x,y;
        for(int i=1;i<=m;i++){
            x=read();y=read();
            n=max(n,max(x,y));
            add(x,y);
        }
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=n;i++)if(!deep[i])dfs(i);
    }
    int main(){
        for(int cases=1;;cases++){
            m=read();
            if(m==0)break;
            printf("Case %d: ",cases);
            init();
            work();
        }
        return 0;
    }
    
  • 相关阅读:
    理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤
    TSQL查询进阶流程控制语句
    效率最高的Excel数据导入(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)
    SQL Service自定义数据类型
    理解SQL SERVER中的逻辑读,预读和物理读
    TSQL查询进阶深入理解子查询
    SQL查询入门(下篇)
    使用SQL进行递归查询
    利用 sys.sysprocesses 检查 Sql Server的阻塞和死锁
    灵活运用 SQL SERVER FOR XML PATH
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9404084.html
Copyright © 2020-2023  润新知