zoukankan      html  css  js  c++  java
  • 洛谷 P2341 BZOJ 1051 [HAOI2006]受欢迎的牛

    题目描述

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

    牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果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

    感想

    2019年8月16日12:39:48:看自己博客学新算法

    最近在纠结写博客那么详细会不会太浪费时间了,毕竟只是给自己或者周围人看的……但今天再次开始搞tarjan,发现自己就写了这一篇文章,还那么简略……以至于还要去其他博客学习……不过我看出来了,当时的代码里,b数组没必要,判断每一条边时使用e数组就好

    2019年8月16日13:27:54 重新写了一遍,WA了,原因是tarjan函数里,把u点入栈以后忘记更新instack数组了。加上就A了(但出栈的时候还是忘记更新instack数组了,所以第二份代码是有锅的。不过也A了,这到底是没必要,还是数据水……留坑)。重写画了半个小时,好长啊,中途还磕磕绊绊,比如tarjan内部的几种判断的顺序啥的……

    解题思路

      tarjan找到强连通分量,然后缩点,统计缩了之后每个强连通分量的出度,如果只有一个出度为零的强连通分量,答案就是这个强连通分量里点的个数;如果出度为零的强连通分量不止一个,那么答案就为0。

      记得Neil做这题的时候曾经疑惑过——如果缩点后得到的图还是成环咋办?那么所有强连通分量出度都不为零了,答案应该为0,但事实上应该所有奶牛都受欢迎了……原来这个算法正确性是这么保证的——tarjan算法有一个性质:求出的强连通分量一定是极大强连通分量,所以缩出来的点肯定不会成环。

    源代码

    2017年7月2日的

    #include<cstdio>
    #include<algorithm>
    
    int n,m;
    
    struct edge{
        int u,v;
    }b[100010];
    
    struct Edge{
        int nxt,to;
    }e[100010];
    int head[100010]={0},cnt=1;
    void add(int u,int v)
    {
        e[cnt]={head[u],v};
        head[u]=cnt++;
    }
    
    int id[100010]={0},index=0;
    int num[100010]={0};
    
    int dfn[100010]={0},low[100010]={0},dfs_time=0;
    int stack[100010]={0},top=0;
    bool instack[100010]={0};
    void tarjan(int u)
    {
        low[u]=dfn[u]=++dfs_time;
        stack[top++]=u;
        instack[u]=1;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(!dfn[v])
                tarjan(v),low[u]=std::min(low[v],low[u]);
            else if(instack[v])
                low[u]=std::min(low[v],low[u]);
        }
        if(dfn[u]==low[u])
        {
            index++;
            int v;
            do{
                v=stack[--top];
                stack[top]=0;
                id[v]=index,instack[v]=0;
                num[index]++;
            }while(v!=u);
        }
    }
    
    int out[100010]={0};
    
    int main()
    {
        //freopen("cow.in","r",stdin);
        //freopen("cow.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1,u,v;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            b[i]={u,v};
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        for(int i=1;i<=m;i++)
            if(id[b[i].u]!=id[b[i].v])
                out[id[b[i].u]]++;
    
        
        int ans=0;
        for(int i=1;i<=index;i++)
            if(!out[i])
            {
                if(ans)
                {
                    printf("0
    ");
                    return 0;
                }
                else ans=num[i];
            }
        printf("%d
    ",ans);
        return 0;
    }

     2019年8月16日13:39:02更新——

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 const int MAXN=1e4+5,MAXM=5e4+5;
     5 
     6 int n,m;
     7 
     8 struct Edge{
     9     int nxt,to;
    10 }e[MAXM];
    11 int cnt=1,head[MAXN];
    12 inline void add(int u,int v)
    13 {
    14     e[cnt]={head[u],v};
    15     head[u]=cnt++;
    16 }
    17 
    18 int dfn[MAXN],low[MAXN],dfst=1;//时间戳们
    19 int stack[MAXN],top=0;
    20 bool instack[MAXN];
    21 int id[MAXN],index=1;//缩点用的新id
    22 int num[MAXN];//统计每个强连通分量大小
    23 int out[MAXN];//统计各强连通分量出度
    24 void tarjan(int u)
    25 {
    26     dfn[u]=low[u]=dfst++;//打时间戳
    27     stack[++top]=u;//入栈
    28     instack[u]=1;
    29     for(int i=head[u];i;i=e[i].nxt)
    30     {
    31         int v=e[i].to;
    32         if(!dfn[v])//树边
    33         {
    34             tarjan(v);
    35             low[u]=std::min(low[u],low[v]);
    36         }
    37         else if(instack[v])//返祖边
    38         {
    39             low[u]=std::min(low[u],low[v]);//暂时先更新low,不急着出栈,以便找到极大强连通分量
    40         }
    41     }
    42     if(low[u]==dfn[u])//得割点一个,出栈缩点
    43     {
    44         do//为啥都在栈里来着?
    45         {
    46             id[stack[top--]]=index;
    47             num[index]++;//这句话可以放在外面O(1)处理
    48         }while(stack[top+1]!=u);
    49         index++;
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     scanf("%d%d",&n,&m);
    56     for(int i=1,u,v;i<=m;i++)
    57     {
    58         scanf("%d%d",&u,&v);
    59         add(u,v);
    60     }
    61     for(int i=1;i<=n;i++)
    62     {
    63         if(!dfn[i]) tarjan(i);
    64     }
    65 
    66     for(int u=1;u<=n;u++)//统计出度
    67     {
    68         for(int i=head[u];i;i=e[i].nxt)
    69         {
    70             int v=e[i].to;
    71             if(id[u]!=id[v])
    72             {
    73                 out[id[u]]++;
    74             }
    75         }
    76     }
    77     int ans=0;
    78     for(int i=1;i<index;i++)
    79     {
    80         if(!out[i])
    81         {
    82             if(ans)
    83             {
    84                 puts("0");
    85                 return 0;
    86             }
    87             ans=num[i];
    88         }
    89     }
    90     printf("%d
    ",ans);
    91     return 0;
    92 }
  • 相关阅读:
    Linux命令ll输出后各个字段的含义
    常用的Linux指令
    纪念逝去的2016
    Grails默认首页的修改
    js中构造字符串若放入Grails中gsp的<g:link>标签出错
    Grails的redirect无法跳转时的一个可能原因
    Grails连接外部数据库注意事项Could not determine Hibernate dialect for database name [Oracle]!
    ICPC2020济南A Matrix Equation
    最后的挣扎
    [省选联考 2020 A/B 卷] 信号传递
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/7107275.html
Copyright © 2011-2022 走看看