• POJ 2186 白书经典 强连通图分量(内附模板)


    题目:https://vjudge.net/problem/POJ-2186

    Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
    popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

    Input

    * Line 1: Two space-separated integers, N and M

    * Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

    Output

    * Line 1: A single integer that is the number of cows who are considered popular by every other cow.

    Sample Input

    3 3
    1 2
    2 1
    2 3
    

    Sample Output

    1
    

    Hint

    Cow 3 is the only cow of high popularity.
     
     
    题意:  每头牛都想当红人   给定n头牛的牛群    和m个有序对   (A,B)(B,C)==》(A,C)
         表示A认为B是红人   B认为C是红人  那么就有  A认为C是红人
       求被其它所有牛认为是红人的牛的个数
     
     
    思路:   假如直接遍历每一个顶点搜索的到  复杂度O(n*m)会超时
     
     
               假如  有(A,B) 和(B,A)那么可以把A和B缩成一个点    
     
     
    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<algorithm>
    #include<map>
    #define maxn 200005
    using namespace std;
    bool used[maxn];         //点是否被遍历
    int n,m;                 //顶点数和边数
    vector<int>mp[50005];    //建图数组
    vector<int>mp2[50005];   //反向边建立图
    vector<int>vs;           //后序遍历顺序的顶点列表
    int cmp[maxn];           //强连通分量的拓扑序

    //建立图
    void add_edge(int from,int to)
    {
        mp[from].push_back(to);    //正反建立图
        mp2[to].push_back(from);
    }

    //第一次dfs遍历
    void dfs(int x)
    {
        used[x]=true;  // 标记
        for(int i=0;i<mp[x].size();i++)
        {
            if(!used[mp[x][i]])dfs(mp[x][i]);   //dfs图
        }
        //cout<<x<<endl;
        vs.push_back(x);    //记录遍历的顺序
    }

    //第二次dfs遍历
    void rdfs(int x,int k)
    {
        used[x]=true;  //标记点
        cmp[x] = k;   //记录属于一个集合
        for(int i = 0; i<mp2[x].size(); i ++)
        {
            if(!used[mp2[x][i]])rdfs(mp2[x][i],k);
        }
    }

    //查询模板  计算强连通图的个数
    int scc()
    {
        memset(used,false,sizeof(used));
        vs.clear();
        for(int i = 0;i < n;i ++)
        {
            if(!used[i])dfs(i);
        }
        memset(used,false,sizeof(used));
        int k=0;
        for(int i=vs.size()-1;i>=0;i--)    //从查询顺序和第一次查询顺序相反
        {
            if(!used[vs[i]])rdfs(vs[i],k++);
        }
            return k;
    }

    int a[maxn],b[maxn];
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<m;i++)
        {
            cin>>a[i]>>b[i];
            add_edge(a[i]-1,b[i]-1);
        }
        int ans=scc();
        int flag=0;
        int num=0;
        //cout<<ans<<endl;
        for(int i=0;i<n;i++)
        {
            if(cmp[i]==ans-1)
            {
                flag=i;
                num++;
            }
        }
       // cout<<flag<<endl;
       //cout<<num<<endl;
        //检查是否从所有点可达
        memset(used,false,sizeof(used));
        rdfs(flag,0);     //重新用强连通分量分解的代码
        for(int i=0;i<n;i++)
        {
            if(!used[i]){
                num=0;
            break;
            }
        }
        cout<<num<<endl;
         return 0;
    }

    /*

    12 16
    2 3
    3 2
    4 3
    4 1
    5 7
    6 3
    6 4
    6 5
    7 6
    8 10
    9 8
    9 7
    10 9
    11 8
    11 10
    12 11

    0

    */

     
     
     
     
     
               
  • 相关阅读:
    grep
    Ubuntu配置sun jdk
    mysqldump导出数据库表结构与数据至本地
    checkbox前后台使用
    MAC OS X 命令行提交本地项目到git
    前端参数传递错误之中英文字符
    微信支付之扫码支付(java版 native原生支付)
    jquery 取消 radio checked 属性,重新选中的问题解决
    消除父级元素对子级元素的点击事件影响
    mysql 双机热备注意事项
  • 原文地址:https://www.cnblogs.com/huangzzz/p/8858807.html
Copyright © 2020-2023  润新知