• bzoj2730矿场搭建——点双连通分量


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

    首先一遍tarjan找出割点,将图缩点,这些大点中如果有只包含一个割点的,那么如果这个割点被去掉,则这个大点与图不连通,所以这个大点内必须有一个出口;

    而如果没有割点,需要建两个出口,以防止一个出口点被去掉;

    方案数就是放出口的大点的size乘积;没有割点则方案数为C(m,2);

    注意自己记录点数。

    代码如下:

    #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
    ",t,k,ans);
        }
        return 0;
    }
  • 相关阅读:
    如何用消息系统避免分布式事务?
    jvm调休,监控
    ClassLoader原理
    JVM结构、GC工作机制详解
    单链表倒置
    hashSet
    HashMap
    hashcode
    深入理解HTTP协议、HTTP协议原理分析
    HTTP协议(详解一)
  • 原文地址:https://www.cnblogs.com/Zinn/p/8886648.html
Copyright © 2020-2023  润新知