zoukankan      html  css  js  c++  java
  • PKU2186 Popular Cows 受欢迎的牛

    题目描述

    每一头牛的愿望就是变成一头最受欢迎的牛。现在有N(N<=10000)头牛,给你M(M<=50000)对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢的。

    输入格式

    第一行两个数N,M。

    接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复)

    N<=10000,M<=50000

    输出格式

    一个数,即有多少头牛被所有的牛认为是受欢迎的


    根据题目中所说的"传递性",显然一个强连通分量里的牛是互相欢迎的。

    根据这一点,我们可以先找出强连通分量,然后缩点。对于得到的DAG,我们再分析一下它的性质。

    首先,如果一头牛被所有牛都欢迎,那么这头牛所在的强连通分量内的所有牛也被所有牛欢迎。并且从所有牛出发,都能够走到这个强连通分量去。所以,如果存在两个及以上出度为0的强连通分量,那么就不存在被所有牛欢迎的牛。那么如果存在被所有牛欢迎的牛,就说明缩完点的图中只有一个出度为0的点,答案为这个强连通分量的大小。

    强连通分量用Tarjan找,总时间复杂度为O(N+M)。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define maxn 10001
    #define maxm 50001
    using namespace std;
    
    struct edge {
        int to,next;
        edge() {}
        edge(const int &_to,const int &_next){ to=_to,next=_next; }
    }e[maxm];
    int head[maxn],k;
    
    int n,m;
    int dfn[maxn],low[maxn],tot;
    int stack[maxn],top;
    bool vis[maxn];
    int col[maxn],cnt,size[maxn],du[maxn];
    inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }
    
    void tarjan(const int &u) {
        dfn[u]=low[u]=++tot;
        stack[++top]=u,vis[u]=true;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
            else if(vis[v]) low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            int v; cnt++;
            do{ v=stack[top--],vis[v]=false,size[cnt]++,col[v]=cnt; }while(u!=v);
        }
    }
    
    inline void print(){
        for(register int i=1;i<=n;i++) {
            for(register int j=head[i];~j;j=e[j].next) if(col[i]!=col[e[j].to]) du[col[i]]++;
        }
        register int flag=false;
        for(register int i=1;i<=cnt;i++) if(!du[i]){
            if(flag){ printf("0
    "); return; }
            flag=i;
        }
        printf("%d
    ",size[flag]);
    }
    
    int main() {
        memset(head,-1,sizeof head);
        scanf("%d%d",&n,&m);
        for(register int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        for(register int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        print();
        return 0;
    }
    
  • 相关阅读:
    磁盘IO性能监控(Linux 和 Windows)
    cacti监控linux和windows磁盘IO
    如何重新划分linux分区大小
    OCX控件打包成CAB并实现数字签名过程
    手把手教你用CAB发布OCX的简单办法
    WebLogic 11g重置用户密码
    rxswift的双向绑定
    投资的三个层次:投资的道与术--投资的一级算法
    《DSL》笔记一、什么是DSL(转)
    编程语言与世界观
  • 原文地址:https://www.cnblogs.com/akura/p/10952065.html
Copyright © 2011-2022 走看看