poj 2186(强连通分量)

题意:
n头奶牛,给出若干个欢迎关系a b,表示a欢迎b,欢迎关系是单向的,但是是可以传递的,如:a欢迎b,b欢迎c,那么a欢迎c 。另外每个奶牛都是欢迎他自己的。求出被所有的奶牛欢迎的奶牛的数目.

方法:对有向图求强连通分量,然后找出所有独立的强连通分量(所谓独立,就是该连通分量里面的点到外面的点没有通路,当然,连通分量外的点是可以有路到强连通分量内的点的),如果独立的强连通分量的数目只有一个,那么,就输出这个强连通分量内解的个数,否则输出无解。

kosaraju:

http://www.nocow.cn/index.php/Kosaraju%E7%AE%97%E6%B3%95

View Code
  1 // File Name: 2186.cpp

  2 // Author: Missa

  3 // Created Time: 2013/2/5 星期二 20:47:56

  4 

  5 #include<iostream>

  6 #include<cstdio>

  7 #include<cstring>

  8 #include<algorithm>

  9 #include<cmath>

 10 #include<queue>

 11 #include<stack>

 12 #include<string>

 13 #include<vector>

 14 #include<cstdlib>

 15 #include<map>

 16 using namespace std;

 17 

 18 //***********************kosaraju**************

 19 const int maxn = 1e4+5;

 20 const int maxm = 5e4+5;

 21 int n,m;

 22 vector <int> adj[maxn];//正向邻接表

 23 vector <int> radj[maxn];//反向邻接表

 24 vector <int> ord;//后续访问顺序

 25 bool vis[maxn];

 26 int ma[maxn];//表示点v属于哪个连通分量

 27 int cnt;//有向图强连通分量的个数

 28 void init()

 29 {

 30     for(int i=0;i<maxn;i++)

 31     {

 32         adj[i].clear();

 33         radj[i].clear();

 34     }

 35     ord.clear();

 36     cnt=0;

 37 }

 38 void dfs1(int v)

 39 {

 40     vis[v]=1;

 41     for(int i=0;i<adj[v].size();i++)

 42         if(!vis[adj[v][i]])

 43             dfs1(adj[v][i]);

 44     ord.push_back(v);

 45 }

 46 void dfs2(int v)

 47 {

 48     vis[v]=1;

 49     ma[v]=cnt;

 50     for(int i=0;i<radj[v].size();i++)

 51         if(!vis[radj[v][i]])

 52             dfs2(radj[v][i]);

 53 }

 54 void kosaraju()

 55 {

 56     memset(vis,0,sizeof(vis));

 57     ord.clear();

 58     for(int i=1;i<=n;i++)//顶点从1--n

 59         if(!vis[i])

 60             dfs1(i);

 61     memset(vis,0,sizeof(vis));

 62     cnt=0;

 63     for(int i=ord.size()-1;i>=0;i--)

 64         if(!vis[ord[i]])

 65         {

 66             cnt++;

 67             dfs2(ord[i]);

 68         }

 69 }

 70 //*********************************************

 71 void solve()

 72 {

 73     kosaraju();

 74     int ans[maxn];

 75     memset(vis,0,sizeof(vis));

 76     memset(ans,0,sizeof(ans));

 77     for(int i=1;i<=n;i++)

 78     {

 79         ans[ma[i]]++;//统计每个连通分量的大小

 80         for(int j=0;j<adj[i].size();j++)

 81         {

 82             int v=adj[i][j];

 83             if(ma[i] != ma[v])//有向边(i,v),若i与v不在一个连通分量

 84                 vis[ma[i]]=1;//i所在的强连通分量出度不为0.

 85         }

 86     }

 87     int flag=0,cow;

 88     for(int i=1;i<=cnt;i++)

 89     {

 90         if(!vis[i])//出度为0

 91         {

 92             cow=i;

 93             flag++;

 94         }

 95     }

 96     if(flag==1)

 97         printf("%d\n",ans[cow]);

 98     else

 99         printf("0\n");//存在多个出度为0。表明至少两组是不互相羡慕的

100 }

101 int main()

102 {

103     while(~scanf("%d%d",&n,&m))

104     {

105         init();

106         for(int i=0;i<m;i++)

107         {

108             int x,y;

109             scanf("%d%d",&x,&y);

110             adj[x].push_back(y);

111             radj[y].push_back(x);//反向边

112         }

113         solve();

114     }

115     return 0;

116 }

117 

118 /*

119 3 3

120 1 2

121 2 1

122 2 3

123  * /

 

你可能感兴趣的:(poj)