题目描述:
有n(n<=10000)头牛,给出m(m<=50000)个关系(x,y),表示牛x认为牛y很popular。
如果牛x认为牛y很popular,而且牛y认为牛z很popular,则牛x认为牛z很popular。
问被其他所有牛都认为很popular的牛有多少头。
题目分析:
转化为有向图。进行强连通缩点(一个强连通分量内的牛互相都认为对方popular)
如果只有一个强连通分量出度为0,则这个强连通分量的点的数量为答案
如果有多个强连通分量出度为零,则答案为0(一个出度为0的强连通分量内的牛,都不认为其他分量的牛是popular的,反之亦然)
代码:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <functional>
#define INF 0x3f3f3f3f
#define P (1000000007)
using namespace std;
typedef long long ll;
struct edge{
int u, v, next;
}g[50010];
int n, m, head[10010], vis[10010], dfn[10010], low[10010], dep;
int cnt, belong[10010], chudu[10010];/*缩后强连通分量数 各点所在强连通分量标记 各强连通分量出度*/
stack<int> stk;
void dfs(int u){
vis[u] = 1;
dfn[u] = low[u] = ++dep;
stk.push(u);
for (int i = head[u]; i != -1; i = g[i].next){
int v = g[i].v;
if (!vis[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (belong[v]==0) /*该点还不属于任何强连通分量*/
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]){
++cnt;
while (1){
int d = stk.top();
belong[d] = cnt;
stk.pop();
if (d == u)break;
}
}
}
int main(){
int u, v, ans;
while (~scanf("%d %d", &n, &m)){
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(belong, 0, sizeof(belong));
memset(chudu, 0, sizeof(chudu));
ans = dep = cnt = 0;
while (stk.size())stk.pop();
for (int i = 0; i < m; i++){
scanf("%d %d", &u, &v);
g[i].u = u;
g[i].v = v;
g[i].next = head[u];
head[u] = i;
}
for (int i = 1; i <= n; i++)
if (vis[i] == 0)
dfs(i);
for (int i = 0; i < m; i++)
if (belong[g[i].u] != belong[g[i].v]){
chudu[belong[g[i].u]]++;
}
for (int i = 1; i <= cnt; i++){
if (chudu[i] == 0){
if (ans == 0){
for (int j = 1; j <= n; j++){
if (belong[j] == i)
ans++;
}
}
else{ /*若出度为0的点数不止一个,则答案为0*/
ans = 0;
break;
}
}
}
printf("%d\n", ans);
}
return 0;
}