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  * /

 

posted @ 2013-02-05 21:37  Missa  阅读(248)  评论(0编辑  收藏  举报