zoukankan      html  css  js  c++  java
  • [BZOJ 2730][HNOI2012]矿场搭建(Tarjan)

    Description

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

    Solution

    求割点,把所有割点去掉后形成的某个连通块如果与两个及以上割点相连,就可以不建救援出口,否则要建

    方案就是这些要建救援出口的连通块的大小乘积(乘法原理)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #define MAXN 505
    typedef long long LL;
    using namespace std;
    int n,m,head[MAXN],cnt,dfn[MAXN],low[MAXN],dfn_clock,tot,num;
    bool cut[MAXN],vis1[MAXN],vis2[MAXN];
    struct Node
    {
        int next,to;
    }Edges[MAXN*2];
    
    void init()
    {
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(cut,0,sizeof(cut));
        memset(vis1,0,sizeof(vis1));
        m=dfn_clock=cnt=0;
    }
    void addedge(int u,int v)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
    }
    void tarjan(int u,int f)
    {
        low[u]=dfn[u]=++dfn_clock;
        int child=0;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(!dfn[v])
            {
                child++;
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u])cut[u]=1;
            }
            else if(v!=f)
            low[u]=min(low[u],dfn[v]);
        }
        if(!f&&child==1)cut[u]=0;
    }
    void dfs(int u)
    {
        vis1[u]=1;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(vis1[v])continue;
            if(!cut[v]) num++,dfs(v);
            else if(!vis2[v])vis2[v]=1,tot++;
        }
    }
    int main()
    {
        int kase=0;
        while(~scanf("%d",&n)&&n)
        {
            ++kase;
            init();
            for(int i=1;i<=n;i++)
            {
                int s,t;
                scanf("%d%d",&s,&t);
                addedge(s,t);
                addedge(t,s);
                m=max(m,s),m=max(m,t);
            }
            LL ans1=0,ans2=1;
            for(int i=1;i<=m;i++)if(!dfn[i])tarjan(i,0);
            for(int i=1;i<=m;i++)
            {
                if(!vis1[i]&&!cut[i])
                {
                    memset(vis2,0,sizeof(vis2));
                    tot=0;num=1;
                    dfs(i);
                    if(tot==1)ans1++,ans2*=num;
                }
            }
            if(!ans1)ans1=2,ans2=1LL*m*(m-1)/2;
            printf("Case %d: %lld %lld
    ",kase,ans1,ans2);
        }
        return 0;
    } 
  • 相关阅读:
    如何查看ubuntu版本
    基于Python与命令行人脸识别项目(系列一)
    问题 B: Curriculum Vitae
    问题 M: 克隆玩具
    1906: 鹊桥相会
    3265: 聪明的矿工
    2363: 完美旗手队列
    2545: 内部收益率
    2544: 台球碰撞
    3272: 公民身份号码
  • 原文地址:https://www.cnblogs.com/Zars19/p/6736223.html
Copyright © 2011-2022 走看看