【HNOI2012/BZOJ2730】矿场搭建 双联通分量

原题走这里

又是一道神奇的题
首先我们会发现在同一个双联通分量内
如果坍塌的不是割点则不会有任何影响
那么我们只考虑割点坍塌的情况

如果某个双连通分量有多于一个割点,则无需设置逃生出口
否则要在非割点的点上设置一个
每个设置了逃生出口双联通分量的大小减去1之后全部乘起来即可
注意特判全图只有一个双联通分量的情况,只需2个逃生出口

代码如下:


#include 
using namespace std;
int k,m,n,s[1011],t[1011],a[1011],dfn[1011],low[1011],head[1011],dfs_clock,top,b[1011],iscut[1011];
struct edge
{
    int v,p;
}e[1010];
inline void addedge(int u,int v)
{
    e[++top]=(edge){v,head[u]};
    head[u]=top;
    e[++top]=(edge){u,head[v]};
    head[v]=top;
}
void dfs1(int u,int fa,bool isroot=0)
{
    dfn[u]=low[u]=++dfs_clock;
    int son_num=0;
    bool flag=0;
    for(int i=head[u];i;i=e[i].p)
    {
        int v=e[i].v;
        if(v==fa)continue;
        if(dfn[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
        else
        {
            dfs1(v,u,0);
            low[u]=min(low[u],low[v]);
            son_num++;
            if((!isroot)&&low[v]>=dfn[u])flag=1;
        }
    }
    if(isroot&&son_num>1)flag=1;
    if(flag)iscut[u]=1;
}
int dfs2(int u,int &temp)
{
    if(b[u])return 0;
    b[u]=1;
    if(iscut[u])
    {
        temp++;
        return 0;
    }
    int ret=1;
    for(int i=head[u];i;i=e[i].p)
    {
        ret+=dfs2(e[i].v,temp);
    }
    return ret;
}
int main()
{
    freopen("bzoj_2730.in","r",stdin);
    freopen("bzoj_2730.out","w",stdout);
    while(cin>>m)
    {
        if(!m)return 0;
        k++;
        top=0;
        memset(head,0,sizeof(head));
        memset(b,0,sizeof(b));
        memset(iscut,0,sizeof(iscut));
        memset(dfn,0,sizeof(dfn));
        for(int i=1;i<=m;i++)
        {
            cin>>s[i]>>t[i];
            a[2*i-1]=s[i];
            a[2*i]=t[i];
        }
        sort(a+1,a+2*m+1);
        int n=unique(a+1,a+2*m+1)-(a+1);
        for(int i=1;i<=m;i++)
        {
            addedge(lower_bound(a+1,a+n+1,s[i])-a,lower_bound(a+1,a+n+1,t[i])-a);
        }
        int ret=0;
        unsigned long long pro_ret=1;
        for(int i=1;i<=n;i++)
        {
            dfs_clock=0;
            if(!dfn[i])dfs1(i,0,1);
        }
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            if((!b[i])&&(!iscut[i]))
            {
                int temp=0;
                unsigned long long pro=dfs2(i,temp);
                if(temp<=1)
                {
                    ret++;
                    pro_ret*=pro;
                }
                for(int i=1;i<=n;i++)
                {
                    if(iscut[i])b[i]=0;
                }
            }
            if(iscut[i])flag=1;
        }
        if(flag)cout<<"Case "<": "<' '<else cout<<"Case "<": "<<2<<' '<1)/2<

你可能感兴趣的:(【HNOI2012/BZOJ2730】矿场搭建 双联通分量)