[HNOI2012]矿场搭建

版权声明:欢迎转载(标记出处),写得不好还请多指教 https://blog.csdn.net/quan_tum/article/details/82428537

传送门
若该连通分量里有大于一个割点,不用建出口,无论哪个割点炸了,都可以到其他的双连通分量。

若该连通分量里只有一个割点,要在这个割点里建一个出口。

若该连通分量里一个割点也没有,就要建两个出口。

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b))?(a):(b)
using namespace std;
const int N=505;
int dfn[N],vis[N],low[N],h[N];
bool cut[N];
ll k,cnt,in,rt,rs,m,n,s1,s2,t,ct;
struct Node{int v,nxt;}a[N*N];
void Init(){
    memset(h,0,sizeof(h));memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));memset(cut,0,sizeof(cut));
    memset(vis,0,sizeof(vis));in=k=m=s1=ct=0;
    s2=1;
}
void add(int u,int v){a[++k]=(Node){v,h[u]};h[u]=k;}
void Tarjan(int x,int fa){
       dfn[x]=low[x]=++in;   
       for(int i=h[x];i;i=a[i].nxt){
            int y=a[i].v;
            if(!dfn[y]){
                Tarjan(y,x);
                low[x]=min(low[x],low[y]);
                if(low[y]>=dfn[x]) x!=rt?cut[x]=1:rs++;
            }else if(y!=fa) low[x]=min(low[x],dfn[y]);
       }
}
void dfs(int x){
    vis[x]=ct;++k;
    for(int i=h[x];i;i=a[i].nxt){
        int y=a[i].v;
        if(cut[y]&&vis[y]!=ct) ++cnt,vis[y]=ct;
        if(!vis[y]) dfs(y);
    }
}
int main(){
    ios::sync_with_stdio(0);
    while(cin>>n&&n){
        Init();
        for(int i=1;i<=n;++i){
            int x,y;cin>>x>>y;
            add(x,y);add(y,x);
            m=max(m,max(x,y));
        }
        for(int i=1;i<=m;++i){
            if(!dfn[i]){
                rt=i;rs=0;
                Tarjan(i,i);
                if(rs>=2) cut[i]=1;
            }
        }
        for(int i=1;i<=m;++i){
            if(!vis[i]&&!cut[i]){
                ++ct;k=cnt=0;dfs(i);
                if(cnt==0) s1+=2,s2*=(k-1)*k/2;
                if(cnt==1) s1+=1,s2*=k;
            }
        }cout<<"Case "<<++t<<": "<<s1<<" "<<s2<<endl;
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/quan_tum/article/details/82428537