• BZOJ2730_矿场搭建_KEY


    题目传送门

    这道题用Tarjan求出点-双连通分量,对联通块做一些玄学操作。

    细节很多,不说了看code。

    code:

    /**************************************************************
        Problem: 2730
        User: yekehe
        Language: C++
        Result: Accepted
        Time:0 ms
        Memory:840 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    int read()
    {
        char c;while(c=getchar(),c<'0'||c>'9');
        int x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
        return x;
    }
     
    int N;
     
    struct list{
        int head[505],nxt[505],To[505],cnt;
        void clear(){memset(head,-1,sizeof head);memset(nxt,-1,sizeof nxt);cnt=0;}
         
        void add(int x,int y)
        {
            To[cnt]=y;
            nxt[cnt]=head[x];
            head[x]=cnt;
            cnt++;
        }
    }W;
     
    int DFN[505],LOW[505],cnt,wif[505];
    void tarjan(int now,int fa)
    {
        int child=0;
        DFN[now]=LOW[now]=++cnt;
            for(int i=W.head[now];i!=-1;i=W.nxt[i]){
                if(!DFN[W.To[i]]){
                    child++;
                    tarjan(W.To[i],now);
                    LOW[now]=min(LOW[now],LOW[W.To[i]]);
                    if(LOW[W.To[i]]>=DFN[now])wif[now]=1;//割顶的判定
                }
                else if(DFN[W.To[i]]<DFN[now]&&W.To[i]!=fa){
                    LOW[now]=min(LOW[now],DFN[W.To[i]]);
                }
            }
        if(fa<0&&child==1)wif[now]=0;
    }//求点-双连通分量
     
    int ct=0;
    int vis[505],tong[505];
    long long cnc;
    void dfs(int now)
    {
        cnc++;//求除了割点的联通块内的其他点的数量
        vis[now]=1;//标记该点被访问
            for(int i=W.head[now];i!=-1;i=W.nxt[i]){
                if(!vis[W.To[i]])
                    if(wif[W.To[i]])tong[W.To[i]]=ct;//用桶记录割顶
                    else dfs(W.To[i]);
            }
    }
     
    int main()
    {
        int TOT=0;
        while((N=read())!=0){
            TOT++;
            W.clear();
            memset(DFN,0,sizeof DFN);
            memset(LOW,0,sizeof LOW);
            memset(tong,0,sizeof tong);
            memset(wif,0,sizeof wif);
            memset(vis,0,sizeof vis);
            cnt=0;
            int TN=0;
                for(int i=1;i<=N;i++){
                    int x=read(),y=read();
                    TN=max(TN,x);TN=max(TN,y);
                    W.add(x,y);W.add(y,x);//双向边
                }
                for(int i=1;i<=TN;i++)
                    if(!DFN[i])tarjan(i,-1);
            int ans=0;
            printf("Case %d: ",TOT);
            long long tot=1;//方案数
           for(int i=1;i<=TN;i++)if(!vis[i]&&!wif[i]){//这个点既不是割顶也没被访问过 cnc=0;//联通块内除了割顶的点的数量 dfs(i); int kkk=0;//求有几个割顶 for(int j=1;j<=TN;j++)if(tong[j]==ct)kkk++; if(!kkk){//如果这个联通块内没有割顶,那么要且只要建两个救助站就好了,可以自己画图 ans+=2; tot=tot*cnc*(cnc-1)/2;//用乘法原理和组合求方案数 } else { if(kkk==1){//有一个割顶 ans++; tot=tot*cnc;//乘以联通块内除了割顶的点的数量 } }//当割顶的数量大于等于2时不能也不需要建救助站。不能是因为要求数量最少,可以自己画图 } printf("%d %lld ",ans,tot); } }
  • 相关阅读:
    [Java多线程]-并发,并行,synchonrized同步的用法
    [大数据可视化]-saiku的源码打包运行/二次开发构建
    [大数据可视化]-saiku的源码包Bulid常见问题和jar包
    [Java多线程]-线程池的基本使用和部分源码解析(创建,执行原理)
    [机器学习]-PCA数据降维:从代码到原理的深入解析
    [Java多线程]-Thread和Runable源码解析之基本方法的运用实例
    [Java多线程]-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
    [Java多线程]-Thread和Runable源码解析
    [机器学习]-Adaboost提升算法从原理到实践
    月是故乡明
  • 原文地址:https://www.cnblogs.com/Cptraser/p/8515751.html
Copyright © 2020-2023  润新知