1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular;如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所有的cows认为popular! 10 */ 11 #include <string> 12 #include <cstdio> 13 #include <cstring> 14 #include <iostream> 15 #include<vector> 16 #define M 10005 17 using namespace std; 18 19 vector<int>ex[M]; 20 vector<int>ey[M]; 21 22 int n, m; 23 int cnt[M];//记录第一次dfs的节点的逆序 24 int vis[M];//标记节点是否已经被访问过了 25 int mark[M];//标记每一个节点是属于哪一个连通分量 26 int ans; 27 int top; 28 29 void dfs1(int u){//出度遍历 30 if(!vis[u]){ 31 vis[u]=1; 32 int len=ex[u].size(); 33 for(int i=0; i<len; ++i){ 34 int v=ex[u][i]; 35 dfs1(v); 36 } 37 cnt[top++]=u; 38 } 39 } 40 41 void dfs2(int u){//入度遍历 42 if(!vis[u]){ 43 vis[u]=1; 44 mark[u]=ans; 45 int len=ey[u].size(); 46 for(int i=0; i<len; ++i){ 47 int v=ey[u][i]; 48 dfs2(v); 49 } 50 } 51 } 52 53 int main(){ 54 while(scanf("%d%d", &n, &m)!=EOF){ 55 while(m--){ 56 int u, v; 57 scanf("%d%d", &u, &v); 58 ex[u].push_back(v); 59 ey[v].push_back(u); 60 } 61 ans=top=0; 62 for(int i=1; i<=n; ++i) 63 if(!vis[i]) 64 dfs1(i); 65 66 memset(vis, 0, sizeof(vis)); 67 68 for(int i=top-1; i>=0; --i) 69 if(!vis[cnt[i]]){ 70 ++ans; 71 dfs2(cnt[i]); 72 } 73 int count=0; 74 int u=0; 75 for(int i=1; i<=n; ++i) 76 if(mark[i]==ans){ 77 ++count; 78 u=i; 79 } 80 memset(vis, 0, sizeof(vis)); 81 dfs2(u); 82 83 for(int i=1; i<=n; ++i)//其他的强连通分量是否都指向了最后一个强连通分量 84 if(!vis[i]){ 85 count=0; 86 break; 87 } 88 printf("%d\n", count); 89 for(int i=1; i<=n; ++i){ 90 ex[i].clear(); 91 ey[i].clear(); 92 } 93 memset(vis, 0, sizeof(vis)); 94 } 95 return 0; 96 }
poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)
时间: 2024-12-28 21:06:58