Popular Cows

来源:互联网 发布:油画制作软件 编辑:程序博客网 时间:2024/05/16 19:54

                              Popular Cows

题目链接:Click Here~ 

题目分析:

    在草原上有N这牛。如果,A牛崇拜B牛,B牛崇拜C牛,则间接的说明A牛崇拜C牛。叫你求出在这N只牛当中除了自己外能被其他N-1只牛崇拜的只数。

算法分析:

   这题看是很简单,其实不然。否则,我也不会写这篇文章了。看到这道题,可能想到强连通还是比较简单的,但是这题的有关图论的本质问题还是有很多的。我研究了很多网上很多人写的代码,都是不能很清楚的说出本质原因的。说以我就写下了这篇博客以供大家参考。

   假设,我们在缩点求出强连通后,为什么可以根据如果只有一个出度为O的强连通缩点。此时,问题就有解呢?这其实是涉及到了图论的问题。下面就给出图来解析。我们假设其中的黑线是已经连完的。而绿色的是假设的。而红色的是必须链接的。

从上图可以看出。如果,没一个点都有一个出度,而只有一个点没有,则说明所有的点一定可以到达没有出度的点那里。因为,你可以假设绿色的连线,那样得到的就会是一个连通图,而这就和强连通缩点相矛盾了。所以,绿色的连线假设是不成立的。只有一种可能就是红色的连线。所以,可以推出本题的答案,就是出度为0的点。

   但是,其实本题还有一个问题,就是如果一开始图不是连通的,那答案就不对了。而我开始想的时候没考虑不连通的图,所以写了一个假设是连通的图。结果AC了。但是不知道这是为什么。

  

#include <iostream>#include <algorithm>#include <vector>#include <stack>#include <cstdio>#include <cstring>using namespace std;const int N = 1e4+5;vector<int> G[N];stack<int> S;bool vst[N];int pre[N],lowlink[N],sccno[N],scc_cnt,dfs_clock;int num[N],in[N],out[N];void Init(){    for(int i = 0;i < N;++i){       vst[i] = false;       num[i] = 0;       in[i] = 0;       out[i] = 0;       G[i].clear();    }    while(!S.empty())S.pop();}void dfs(int u){    pre[u] = lowlink[u] = ++dfs_clock;    S.push(u);    for(int i = 0;i < G[u].size();++i){       int v = G[u][i];       if(!pre[v]){          dfs(v);          lowlink[u] = min(lowlink[u],lowlink[v]);       }       else       if(!sccno[v])          lowlink[u] = min(lowlink[u],pre[v]);    }    if(lowlink[u]==pre[u]){       int x,cnt = 0;       scc_cnt++;       do       {           x = S.top();           S.pop();           sccno[x] = scc_cnt;           cnt++;       }while(x!=u);       num[scc_cnt] = cnt;    }}void find_scc(int n){    dfs_clock = scc_cnt = 0;    memset(lowlink,0,sizeof(lowlink));    memset(pre,0,sizeof(pre));    for(int i = 1;i <= n;++i)      if(!pre[i])dfs(i);}int main(){    int n,m,a,b;    while(~scanf("%d%d",&n,&m))    {        Init();        for(int i = 0; i < m;++i){           scanf("%d%d",&a,&b);           G[a].push_back(b);        }        find_scc(n);        for(int u = 1;u <= n;++u)          for(int i = 0;i < G[u].size();++i){             int v = G[u][i];             if(sccno[u]!=sccno[v]){                 in[sccno[v]]++;                 out[sccno[u]]++;             }          }        int r,cnt = 0;        for(int i = 1;i <= scc_cnt;++i){            if(out[i]==0){              cnt++;              r = i;            }        }        if(cnt == 1){            printf("%d\n",num[r]);        }        else           printf("0\n");    }    return 0;}






2 0
原创粉丝点击