zoukankan      html  css  js  c++  java
  • BZOJ1051|HAOI2006受欢迎的牛|强连通分量

    Description
    每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
    Input
    第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
    Output
    一个数,即有多少头牛被所有的牛认为是受欢迎的。
    Sample Input
    3 3
    1 2
    2 1
    2 3
    Sample Output
    1【数据范围】
    10%的数据N<=20, M<=50
    30%的数据N<=1000,M<=20000
    70%的数据N<=5000,M<=50000
    100%的数据N<=10000,M<=50000
    分析:tarjan强连通分量求缩点重构图,出度为0的点若只有一个则输出其代表强连通分量的大小,否则无解。因为显然若有两个出度为0的点,两点之间不能相互欢迎。模板题。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    int n,m;
    int tot=0,cnt=0,top=0;
    struct node{
           int to,next;
    }e[50001],d[50001];
    
    int head[10001];
    int dfn[10001],low[10001],q[10001];
    int scc=0,h[10001],belong[10001],hav[10001];//scc是强连通分量的个数 
    bool vis[10001],inq[10001];
    int ans=0;
    
    void dfs(int a)
    {
         int now;
         inq[a]=vis[a]=1;
         low[a]=dfn[a]=++cnt;
         q[++top]=a;
         int c=head[a];
         while(c)
         {
            if (!vis[e[c].to])
            {
                dfs(e[c].to);
                low[a]=min(low[a],low[e[c].to]);
            }
            else if (inq[e[c].to]) low[a]=min(low[a],dfn[e[c].to]);
            c=e[c].next;
        }
        if (low[a]==dfn[a])
        {
           scc++;
           while (now!=a)
           {
                 now=q[top--];
                 inq[now]=0;
                 belong[now]=scc;
                 ++hav[scc];
           }
        }
    }             
    
    void rebuild()
    {
         cnt=0;
         for (int i=1; i<=n; i++)
         {
             int c=head[i];
             while (c)
             {
                   if (belong[e[c].to]!=belong[i])
                   {
                      d[++cnt].to=belong[e[c].to];
                      d[cnt].next=h[i];
                      h[i]=cnt;
                   }
                   c=d[c].next;
             }
         }
    }
    
    void work()
    {
        for (int i=1; i<=scc; i++)
            if (!h[i])
                     {
                                 if (ans)
                                 {
                                           ans=0; return;
                              }
                              else ans=hav[i];
                              if (i==1) cout << hav[i]<< endl; 
                     }
          
    }
    
    void tarjan()
    {
           for (int i=1; i<=n; i++) if (!vis[i]) dfs(i);
        rebuild();
    }
    
    int main()
    {
        
        cin >> n >> m;
        for (int i=1; i<=m; i++) 
        {
            int x,y,z;
            cin >> x >> y;
            e[++tot].to=y; e[tot].next=head[x]; head[x]=tot;
        }
        tarjan();
        work();
        cout << ans;
        system("pause");
        return 0;
    }
  • 相关阅读:
    【C语言】学习笔记5——指针(1)
    【C语言】学习笔记4——数组
    【leetcode】Contest98
    【Python】从0开始写爬虫——豆瓣电影
    C# WPF 文件复制,相对路径
    WPF DataGrid多表头/列头,多行头,合并单元格,一列占据多行
    WPF Image Source 设置相对路径图片
    WPF Blend 一个动画结束后另一个动画开始执行(一个一个执行)
    WPF 操作XML 读写
    WPF 选择电脑文件显示路径,弹出资源管理器,打开文件
  • 原文地址:https://www.cnblogs.com/Shymuel/p/4656304.html
Copyright © 2011-2022 走看看