首页 > 代码库 > POJ2186 Popular Cows 【强连通分量Kosaraju】
POJ2186 Popular Cows 【强连通分量Kosaraju】
Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 23445 | Accepted: 9605 |
Description
Every cow‘s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3 1 2 2 1 2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
Source
USACO 2003 Fall
题意:可以转换成“给定一些有向路,求有多少个点可以由其余的任意点到达。”
题解:第一道强连通分量的题,大致总结下Kosaraju算法:求强连通分量主要是为了简化图的构造,如果分量外的一个点能到达分量内的其中一个点,那么它必定能到达分量内的所有点,所以某种程度上,强连通分量可以简化成一个点。具体的求解过程是:1、任意选定一个点开始对原图进行深搜,记录每个点离开时的时间(更确切的说是求每个时间对应哪个点离开);2、对原图的反图进行深搜,步骤一中最后离开的点最先开始深搜,每次将同一棵树中的点都哈希成同一个值,最后有多少棵树就有多少个强连通分量。
这题最后所有点都哈希完成后实际上构成了一个DAG,如果新图中出度为0的点只有一个那么有解,解为该出度为0的强连通分量中原来点的个数。若出度为0的点不止一个,那么无解,因为有两群牛互不崇拜,此时答案为0.在判断连通分量是否有出度时有个小技巧,就是在对反图DFS时若发现连接到的点已访问且它的哈希值与当前访问点的哈希值不同,那么这个被连接到的点对应的联通分量是有出度的。然后还需记录每个连通分量的点数。
#include <stdio.h> #include <string.h> #define maxn 10002 #define maxm 50002 int head0[maxn], head1[maxn], id; int count[maxn], num[maxn], hash[maxn]; struct Node{ int t0, next0, t1, next1; } E[maxm]; bool vis[maxn], out[maxn]; void addEdge(int u, int v) { E[id].t0 = v; E[id].next0 = head0[u]; head0[u] = id; E[id].t1 = u; E[id].next1 = head1[v]; head1[v] = id++; } void getMap(int n, int m) { int i, u, v; id = 0; memset(head0, -1, sizeof(int) * (n + 1)); //save time memset(head1, -1, sizeof(int) * (n + 1)); for(i = 0; i < m; ++i){ scanf("%d%d", &u, &v); addEdge(u, v); } } void DFS0(int pos, int& sig) { vis[pos] = 1; int i; for(i = head0[pos]; i != -1; i = E[i].next0){ if(!vis[E[i].t0]) DFS0(E[i].t0, sig); } num[++sig] = pos; } void DFS1(int pos, int sig) { vis[pos] = 1; hash[pos] = sig; int i; ++count[sig]; for(i = head1[pos]; i != -1; i = E[i].next1){ if(!vis[E[i].t1]) DFS1(E[i].t1, sig); else if(hash[E[i].t1] != hash[pos]) out[hash[E[i].t1]] = 1; } } void solve(int n) //Kosaraju { int i, sig = 0, tmp = 0, ans; memset(vis, 0, sizeof(bool) * (n + 1)); for(i = 1; i <= n; ++i) if(!vis[i]) DFS0(i, sig); memset(vis, 0, sizeof(bool) * (n + 1)); memset(count, 0, sizeof(int) * (n + 1)); memset(out, 0, sizeof(bool) * (n + 1)); i = sig; sig = 0; for(; i; --i) if(!vis[num[i]]) DFS1(num[i], ++sig); for(i = 1; i <= sig; ++i) if(!out[i]) ++tmp, ans = count[i]; //printf("sig%d\n", sig); if(tmp == 1) printf("%d\n", ans); else printf("0\n"); } int main() { int n, m; while(scanf("%d%d", &n, &m) == 2){ getMap(n, m); solve(n); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。