bzoj2730礦場搭建——點雙連通份量

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2730php

首先一遍tarjan找出割點,將圖縮點,這些大點中若是有隻包含一個割點的,那麼若是這個割點被去掉,則這個大點與圖不連通,因此這個大點內必須有一個出口;ios

而若是沒有割點,須要建兩個出口,以防止一個出口點被去掉;ide

方案數就是放出口的大點的size乘積;沒有割點則方案數爲C(m,2);spa

注意本身記錄點數。get

代碼以下:string

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int const MAXN=505;
vector<int>dcc[MAXN];
int t,n,m,siz,tim,ct,head[MAXN],dfn[MAXN],low[MAXN],num,k;
long long ans;
bool vis1[MAXN],vis2[MAXN],cut[MAXN];
struct N{
    int to,next;
    N(int t=0,int n=0):to(t),next(n) {}
}edge[MAXN<<2];
void add(int x,int y)
{
    edge[++ct]=N(y,head[x]);head[x]=ct;
    edge[++ct]=N(x,head[y]);head[y]=ct;
}
void tarjan(int x,int f)
{
    dfn[x]=low[x]=++tim;
    int fl=0;
    for(int i=head[x],u;i;i=edge[i].next)
    {
        if(edge[i].to==f)continue;
        if(!dfn[u=edge[i].to])
        {
            fl++;
            tarjan(u,x);
            low[x]=min(low[x],low[u]);
            if(low[u]>=dfn[x])/*fl++,*/cut[x]=1;
        }
        else low[x]=min(low[x],dfn[u]);
    }
    if(!f&&fl==1)cut[x]=0;
}
int dfs(int x)
{
    int siz=1;
    vis1[x]=1;
    for(int i=head[x],u;i;i=edge[i].next)
    {
        if(vis1[u=edge[i].to]||vis2[u])continue;
        if(!cut[u])siz+=dfs(u);
//        if(!cut[u])siz++,dfs(u);
        else if(!vis2[u])vis2[u]=1,num++;
    }
    return siz;
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        if(!n)return 0;
        t++;ct=0;
        tim=0;m=0;//
        memset(dfn,0,sizeof dfn);
        memset(low,0,sizeof low);
        memset(cut,0,sizeof cut);
        memset(head,0,sizeof head);
        memset(vis1,0,sizeof vis1);
        int x,y;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            m=max(m,x);m=max(m,y);
        }
        for(int i=1;i<=m;i++)
            if(!dfn[i])tarjan(i,0);
        ans=1;k=0;
        for(int i=1;i<=m;i++)
            if(!vis1[i]&&!cut[i])//不能是割點 
            {
                num=0;
                memset(vis2,0,sizeof vis2);
                siz=dfs(i);
                if(num==1)k++,ans*=siz;
            }
        if(!k)k=2,ans=(long long)m*(m-1)/2;//m!
        printf("Case %d: %d %lld\n",t,k,ans);
    }
    return 0;
}
相關文章
相關標籤/搜索