• 受欢迎的牛


    题目背景

    本题测试数据已修复。

    题目描述

    每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

    牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

    欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

    算出有多少头奶牛可以当明星。

    输入格式

     第一行:两个用空格分开的整数:N和M

     第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

    输出格式

     第一行:单独一个整数,表示明星奶牛的数量

    输入输出样例

    输入 #1
    3 3
    1 2
    2 1
    2 3
    输出 #1
    1

    说明/提示

    只有 3 号奶牛可以做明星

    【数据范围】

    10%的数据N<=20, M<=50

    30%的数据N<=1000,M<=20000

    70%的数据N<=5000,M<=50000

    100%的数据N<=10000,M<=50000

    Tarjan算法,倒序建边,这样会提高效率。

    受欢迎的奶牛只有可能是图中唯一的出度为零的强连通分量中的所有奶牛,所以若出现两个以上出度为0的强连通分量则不存在明星奶牛,因为那几个出度为零的分量的爱慕无法传递出去。那唯一的分量能受到其他分量的爱慕同时在分量内相互传递,所以该分量中的所有奶牛都是明星。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int Q=10005;
    
    const int N=50005;
    
    int to[N],nex[N],fir[Q];
    int ccc,num,dfn[Q],low[Q],d[Q],s1[Q];
    int tot=0,ch[Q],n,m;
    int top,s2[Q];
    
    inline void add(int x,int y){
        to[++tot]=y;
        nex[tot]=fir[x];
        fir[x]=tot;
    }
    
    void Tarjan(int u){
        dfn[u]=low[u]=++num;
        s2[++top]=u;
        for(int i=fir[u];i;i=nex[i]){
            int v=to[i];
            if(!dfn[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else{
                if(!ch[v]){
                    low[u]=min(low[u],dfn[v]);
                }
            }
        }
        if(low[u]==dfn[u]){
            ch[u]=++ccc;
            ++s1[ccc];
            while(s2[top]!=u){
                ++s1[ccc];
                ch[s2[top]]=ccc;
                --top;
            }
            --top;
        }
    }
    
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(y,x);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]){
                Tarjan(i);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=fir[i];j;j=nex[j]){
                if(ch[i]!=ch[to[j]]){
                    d[ch[to[j]]]++;
                }
            }
        }
        int ans=0,u=0;
        for(int i=1;i<=ccc;i++){
            if(!d[i]){
                ans=s1[i];
                u++;
            }
        }
        if(u==1){
            printf("%d
    ",ans);
        }
        else{
            printf("0
    ");
        }
        return 0;
    }
  • 相关阅读:
    最小生成树的解法
    51nod 1212 无向图最小生成树
    greater()和less()的使用
    51nod1183 编辑距离
    51nod 1181 质数中的质数(质数筛法)
    upper_bound和lower_bound的用法
    线段树最全模板
    bryce1010专题训练——线段树习题汇总
    51nod 1174 区间中最大的数
    51nod 1113 矩阵快速幂
  • 原文地址:https://www.cnblogs.com/hrj1/p/11154711.html
Copyright © 2020-2023  润新知