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

    今天学了强连通分量的Tarjan算法,做了这道类似于板子题的题(尽管我调了1.5h)。主要的思路是用Tarjan缩点之后,求每个点的入度(实际上是出度,因为我是反着连边的)。如果

    有且只有一个点的入度大于零,那个强连通分量里有的点的个数就是答案。具体实现见代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define maxn 10010
     6 #define maxm 50010
     7 using namespace std;
     8 int dfn[maxn],low[maxn],st[maxn],inn[maxn],head[maxm];
     9 int de[maxn],si[maxn];
    10 int n,m,cnt,top,inl,num;
    11 struct node
    12 {
    13     int u,v,nex;
    14 }edge[maxm];
    15 inline int read() 
    16 {
    17     int x=0;
    18     bool f=1;
    19     char c=getchar();
    20     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
    21     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    22     if(f) return x;
    23     return 0-x;
    24 }
    25 inline void write(int x)
    26 {
    27     if(x<0){putchar('-');x=-x;}
    28     if(x>9)write(x/10);
    29     putchar(x%10+'0');
    30 }
    31 inline void add(int x,int y)
    32 {
    33     cnt++;
    34     edge[cnt].u=x;
    35     edge[cnt].v=y;
    36     edge[cnt].nex=head[x];
    37     head[x]=cnt;
    38 }
    39 inline void Tarjan(int from)//用Tarjan缩点 
    40 {
    41     dfn[from]=low[from]=++num;
    42     st[++top]=from;
    43     for(int i=head[from];i!=-1;i=edge[i].nex)
    44     {
    45         int to=edge[i].v;
    46         if(!dfn[to])
    47         {
    48             Tarjan(to);
    49             low[from]=min(low[from],low[to]);
    50         }
    51         else if(!inn[to])
    52             low[from]=min(low[from],dfn[to]);
    53     }
    54     if(low[from]==dfn[from])
    55     {
    56         inn[from]=++inl;
    57         ++si[inl];//记录每个强连通分量里有多少个点 
    58         while(st[top]!=from)
    59         {
    60             ++si[inl];//同上 
    61             inn[st[top]]=inl;
    62             --top;
    63         }
    64         --top;
    65     }
    66 }
    67 int main()
    68 {
    69     memset(head,-1,sizeof(head));
    70     n=read();m=read();
    71     for(int i=1;i<=m;i++)
    72     {
    73         int x,y;
    74         x=read();y=read();
    75         add(y,x);//反着连边,这样就可以求入度而不是出度了 
    76     }
    77     for(int i=1;i<=n;i++)
    78         if(!dfn[i])
    79             Tarjan(i);//缩点 
    80     for(int i=1;i<=n;i++)
    81        for(int j=head[i];j!=-1;j=edge[j].nex)
    82            if(inn[i]!=inn[edge[j].v]) de[inn[edge[j].v]]++;//更新入度 
    83     int ans=0,u=0;
    84     for(int i=1;i<=inl;i++)
    85     {
    86         if(!de[i])//如果入度大于零 
    87         {
    88             ans=si[i];//赋值 
    89             u++;//记录有几个点符合条件 
    90         }
    91     }
    92     if(u==1)//判断是否有且仅有一个入度大于零的点 
    93         write(ans);
    94     else 
    95         write(0);//否则输出无解 
    96     return 0;
    97 }
    请各位大佬斧正(反正我不认识斧正是什么意思)
  • 相关阅读:
    css实现文字渐变
    mySql中Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre的问题
    mysql不等于判断时,空值过滤问题
    SpringBoot中maven打包,启动报没有主清单属性
    MySQL插入数据时报错Cause: java.sql.SQLException: #HY000的解决方法
    SpringCloud中Feign服务调用请求方式及参数总结
    linux查看占用端口号的程序及pid
    Ant Design Pro 改变默认启动端口号
    启动jar包并生成日志的linux脚本
    JavaWeb中验证码校验的功能实现
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/11237703.html
Copyright © 2011-2022 走看看