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

    受欢迎的牛 jdoj-neooj-1076

        题目大意:给你n个点,m条单项边,求可以和所有点联通的点的个数。

        注释:n<=10,000,m<=50,000

          想法:这题也是一道tarjan裸题,让我来A掉吧!这题和爱在心中(爱在心中?猛戳)类似,只不过这题有坑... ...用panxf的模板A不掉这道题... ...为什么呢?因为n的数据范围,会MLE。但是我们发现,这道题只需要求出强连通分量之中点的个数。所以,我们可以将原本记录强连通分量的点的数组f压成一维。但是,我们不可以用邻接矩阵来存边了。同样的,我们用链式前向星,保证不会MLE。而且,我们在这里需要作出一个特判(不然会WA掉),就是如果存在一个点,这个点入度和出度都为0,最后的答案一定为0,这是显然的。下面,我们想怎样才能正确的求出个数。同样的,我们枚举出度为0的强连通分量,如果个数大于1,显然个数为0。否则,就是这个强联通分量的个数。

        最后,附上丑陋的代码... ...

     1 #include <iostream>
     2 #include <cstdio>
     3 #define N 10010
     4 #define M 50010
     5 using namespace std;
     6 int x[M],y[M];
     7 int to[M],nxt[M],head[N],mid;
     8 int z[N],deep[N],low[N],f[N];
     9 int inwhat[N],chu[N];
    10 int tot,top,ans;
    11 bool v[N],isv1[N],isv2[N];
    12 int inz[N];
    13 void add(int a,int b)//存边 
    14 {
    15     to[++mid]=b;
    16     nxt[mid]=head[a];
    17     head[a]=mid;
    18 }
    19 int n;
    20 void tarjan(int x)//tarjan 
    21 {
    22     z[++top]=x;
    23     v[x]=inz[x]=1;
    24     low[x]=deep[x]=++tot;
    25     for(int i=head[x];i;i=nxt[i])//枚举链式前向星 
    26     {
    27         if(!v[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
    28         else if(inz[to[i]]) low[x]=min(low[x],deep[to[i]]);
    29     }
    30     if(deep[x]==low[x])
    31     {
    32         int t;
    33         ans++;
    34         do
    35         {
    36             t=z[top--];inz[t]=0;
    37             f[ans]++;//这里不用记录强连通分量里具体的点,只需要个数即可。 
    38             inwhat[t]=ans;
    39         }while(t!=x);
    40     }
    41 }
    42 int main()
    43 {
    44     int m;
    45     scanf("%d%d",&n,&m);
    46     int a,b;
    47     for(int i=1;i<=m;i++)
    48     {
    49         scanf("%d%d",&x[i],&y[i]);
    50         isv1[x[i]]=1;//出度 
    51         isv2[y[i]]=1;//入度 
    52         add(x[i],y[i]);
    53     }
    54     for(int i=1;i<=n;i++)
    55     {
    56         if(isv1[i]&&!v[i]) tarjan(i);//枚举整张图 
    57     }
    58     if(n>=2)//特判 
    59     {
    60         for(int i=1;i<=n;i++) if(isv1[i]==0&&isv2[i]==0)
    61         {
    62             printf("0
    ");
    63             return 0;
    64         }
    65     }
    66     for(int i=1;i<=m;i++)
    67     {
    68         if(inwhat[x[i]]!=inwhat[y[i]]) chu[inwhat[x[i]]]++;
    69     }
    70     int cnt=0;
    71     int middle=0;
    72     for(int i=1;i<=ans;++i) if(chu[i]==0) cnt++,middle=i;
    73     if(cnt>1)
    74     {
    75         printf("0
    ");
    76         return 0;
    77     }
    78     else printf("%d
    ",f[middle]);//输出即可。 
    79     return 0;
    80 }

        小结:tarjan是一个O(n)的算法,极其经典,正在getting中。

          错误:在记录出度的时候,不是chu[x[i]]++,而是chu[inwhat[x[i]]]++。

  • 相关阅读:
    Cassandra开发入门文档第三部分(非规范化关系结构、批处理)
    Cassandra开发入门文档第二部分(timeuuid类型、复合主键、静态字段详解)
    Cassandra开发入门文档第一部分
    Flume的Source、Sink总结,及常用使用场景
    Libgdx学习笔记:分享自己写的异步加载
    jquery easyui toolbar 分割线问题
    easyui datagrid设置fit: true后,页面显示不全的情况
    CentOS下安装JDK1.7
    CentOS 7搭建SVN服务器
    SWT中ole/activex实践--操作word的一个例子
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8313248.html
Copyright © 2011-2022 走看看