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;
    } 
  • 相关阅读:
    【MySQL】MySQL之备份
    【MySQL】MySQL之导入和导出
    MySQL逻辑备份之MySQLDump
    【Perl】Linux下安装Perl
    【MySQL】MySQL NDB Cluster维护
    【MySQL】MySQL NDB Cluster安装
    Linux服务器开启ssh服务,实现ssh远程登陆!
    PDO异常处理
    PHP异常处理
    PDO中的事务处理
  • 原文地址:https://www.cnblogs.com/Zars19/p/6736223.html
Copyright © 2011-2022 走看看