Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
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.
————————————————————————————————————————————————————————————————————————————————————————————————
题意:N个奶牛有M对仰慕关系,给出u、v表示u仰慕v,问有几头奶牛受到其余所有奶牛的仰慕。(仰慕关系具有传递性)
思路:每个强连通分量当中,结点两两可达,也就是说每个奶牛相互仰慕。这就是一个朋友圈。给每个朋友圈编号,将它们缩成一个点。缩点之后,就得到了若干个朋友圈。每个朋友圈就是一个强连通分量。
如果朋友圈a到朋友圈b之间有边,那么朋友圈a里面的所有奶牛都仰慕朋友圈b。
这个时候看这些点的出度。出度为0的点就是被所有奶牛仰慕的点。
但是如果出度为0的点超过1个,说明没有任何一个奶牛被所有其他奶牛仰慕。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stack>
#define Mem(f, x) memset(f, x, sizeof(f))
#define PB push_back
using namespace std;
const int N = 1e4+5, M = 5e4+5;;
int dfn[N], scc_id[N], head[N], out[N], line[M][2];
int deep, scc_cnt, tot, n, m;
stack <int> s;
struct Edge {
int v, next;
Edge(){}
Edge(int _v, int _next):
v(_v), next(_next){}
}e[M];
void __init__()
{
for(int i = 0; i < n; i++) {
out[i] = dfn[i] = scc_id[i] = 0;
head[i] = -1;
}
tot = deep = scc_cnt = 0;
}
void add(int u, int v)
{
e[tot] = Edge(v, head[u]);
head[u] = tot++;
}
int dfs(int u)
{
int lowu = dfn[u] = ++deep;
s.push(u);
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(!dfn[v]) {
int lowv = dfs(v);
lowu = min(lowu, lowv);
}
else if(!scc_id[v]) {
lowu = min(lowu, dfn[v]);
}
}
if(lowu == dfn[u]) {
scc_cnt++;
while(1) {
int x = s.top(); s.pop();
scc_id[x] = scc_cnt;
if(x == u) break;
}
}
return lowu;
}
int main()
{
#ifdef J_Sure
freopen("000.in", "r", stdin);
//freopen("999.out", "w", stdout);
#endif
while(~scanf("%d%d", &n, &m)) {
__init__();
for(int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
u--; v--;
line[i][0] = u; line[i][1] = v;
add(u, v);
}
for(int i = 0; i < n; i++) {
if(!dfn[i]) dfs(i);
}
//缩点:把scc_id所储存的强连通分量标号当作顶点
for(int i = 0; i < m; i++) {
int u = scc_id[line[i][0]], v = scc_id[line[i][1]];
if(u != v) out[u]++;
}
//统计出度为0的点,多于1个说明不只一头牛是终点
int god = 0, who;
for(int i = 1; i <= scc_cnt; i++) {
if(!out[i]) {
god++;
if(god > 1) break;
who = i;
}
}
int ans = 0;
if(god == 1) {
for(int i = 0; i < n; i++) {
if(scc_id[i] == who) ans++;
}
printf("%d\n", ans);
}
else puts("0");
}
return 0;
}