zoukankan      html  css  js  c++  java
  • 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); } }
  • 相关阅读:
    深入理解幂等性(转)
    Mysql数据库表结构设计准则
    nodejs以对象做对象的key导致value一直被覆盖
    数组常用方法
    css选择器总结
    CSS 选择器权重计算规则
    ElementUI select
    linux-sed命令
    vue 组件数据传递:
    vue视频: 自定义指令 && 拖拽 && 自定义键盘信息
  • 原文地址:https://www.cnblogs.com/Cptraser/p/8515751.html
Copyright © 2011-2022 走看看