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