• POJ 2186 Popular cows(Kosaraju+强联通分量模板)


    题目链接:http://poj.org/problem?id=2186

    题目大意:给定N头牛和M个有序对(A,B),(A,B)表示A牛认为B牛是红人,该关系具有传递性,如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人。求被其他所有牛认为是红牛的牛的总数。

    解题思路:把所有牛看成顶点,把有序对(A,B)看成从A到B的有向边,那么题目就变成了求所有顶点都可到达的顶点的总数。我们可以得到一个结论,如果一个强连通分量里有一头牛被认为是红人,那么该强联通分量里的所有牛都是红人,这显然是正确的。由于我用的是Kosaraju求强联通分量,根据该算法性质,红牛只会在拓扑序最后的强联通分量里,我只需要找到最后一块强联通分量,取其中一个顶点,看是否所有点都可以到达即可。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 using namespace std; 
     6 const int N=1e4+5;
     7 
     8 vector<int>G[N];//图的邻接表 
     9 vector<int>rG[N];//反向图的邻接表 
    10 vector<int>vs;//后序遍历的顺序的顶点列表 
    11 bool used[N];//记录点是否被访问 
    12 int cmp[N];//cmp[i]表示点i所属强联通分量的拓扑序 
    13 
    14 int V,E;
    15 
    16 void addedge(int u,int v){
    17     G[u].push_back(v);
    18     rG[v].push_back(u);
    19 } 
    20 
    21 void dfs(int v){
    22     used[v]=true;
    23     for(int i=0;i<G[v].size();i++){
    24         if(!used[G[v][i]])
    25             dfs(G[v][i]);
    26     }
    27     //回溯前进行标号 
    28     vs.push_back(v);
    29 }
    30 
    31 void rdfs(int v,int k){
    32     used[v]=true;
    33     //点v属于第k个强连通分量 
    34     cmp[v]=k;
    35     for(int i=0;i<rG[v].size();i++){
    36         if(!used[rG[v][i]])
    37             rdfs(rG[v][i],k);
    38     }
    39 }
    40 
    41 int scc(){
    42     memset(used,false,sizeof(used));
    43     vs.clear();
    44     //第一次DFS 
    45     for(int i=1;i<=V;i++){
    46         if(!used[i])
    47             dfs(i);
    48     }
    49     memset(used,false,sizeof(used));
    50     int k=0;//强联通分量块数 
    51     //第二次DFS
    52     for(int i=vs.size()-1;i>=0;i--){
    53         if(!used[vs[i]]) 
    54             rdfs(vs[i],++k);
    55     }
    56     return k;
    57 }
    58 
    59 void solve(){
    60     //获得强联通块数 
    61     int n=scc();
    62     //统计备选解的个数 
    63     int u=0,num=0;
    64     for(int i=1;i<=V;i++){
    65         if(cmp[i]==n){
    66             u=i;
    67             num++;
    68         }
    69     }
    70     //检查是否所有点可达
    71     memset(used,0,sizeof(used));
    72     rdfs(u,0);
    73     
    74     for(int i=1;i<=V;i++){
    75         if(!used[i]){
    76             num=0;
    77             break;
    78         }
    79     }
    80     for(int i=1;i<=V;i++){
    81         cout<<"i="<<i<<"  cmp="<<cmp[i]<<endl;
    82     }
    83     printf("%d
    ",num);
    84 }
    85 
    86 int main(){
    87     scanf("%d%d",&V,&E);
    88     for(int i=1;i<=E;i++){
    89         int u,v;
    90         scanf("%d%d",&u,&v);
    91         addedge(u,v);
    92     }
    93     solve();
    94     return 0; 
    95 } 
  • 相关阅读:
    3.node.js AssertionError: false == true错误解决
    9.获取当前时区时间和utc时间的工具方法
    2.Express封装mysq方法
    1.Express初识
    poj 3617
    前缀和
    pop 反序列化
    Reverse前两个题
    前两个Web题
    Misc
  • 原文地址:https://www.cnblogs.com/fu3638/p/7247843.html
Copyright © 2020-2023  润新知