注意到被所有牛欢迎的牛会组成一个强联通分量,先求强联通分量,然后如果只有一个出度为0的强联通分量,那这个强联通分量内点的个数即为所求;否则答案为0。
#include <stdio.h>
#include <string.h>
#include <vector>
#include <stack>
using namespace std;
#define MIN(a,b) ((a)<(b)?(a):(b))
#define N 10005 // 题目中可能的最大点数
stack<int>sta; // 存储已遍历的结点
vector<int>gra[N]; // 邻接表表示图
int dfn[N]; // 深度优先搜索访问次序
int low[N]; // 能追溯到的最早的次序
int InStack[N]; // 检查是否在栈中(2为在栈中,1为已访问,且不在栈中,0为不在)
vector<int> Component[N]; // 获得强连通分量结果
int InComponent[N]; // 记录每个点在第几号强连通分量里
int Index,ComponentNumber; // 索引号,强连通分量个数
int n, m; // 点数,边数
int in[N],out[N];
void init(void)
{
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(InStack, 0, sizeof(InStack));
Index = ComponentNumber = 0;
for (int i = 1; i <= n; ++ i)
{
gra[i].clear();
Component[i].clear();
}
while(!sta.empty())
sta.pop();
}
void tarjan(int u)
{
InStack[u] = 2;
low[u] = dfn[u] = ++ Index;
sta.push(u);
for (int i = 0; i < gra[u].size(); ++ i)
{
int t = gra[u][i];
if (dfn[t] == 0)
{
tarjan(t);
low[u] = MIN(low[u], low[t]);
}
else if (InStack[t] == 2)
{
low[u] = MIN(low[u], dfn[t]);
}
}
if (low[u] == dfn[u])
{
++ ComponentNumber;
while (!sta.empty())
{
int j = sta.top();
sta.pop();
InStack[j] = 1;
Component[ComponentNumber].push_back(j);
InComponent[j]=ComponentNumber;
if (j == u)
break;
}
}
}
void input(void)
{
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
gra[a].push_back(b);
}
}
void solve(void)
{
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
input();
solve();
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=1;i<=n;i++)
for(int j=0;j<gra[i].size();j++)
{
if(InComponent[i]!=InComponent[gra[i][j]])
out[InComponent[i]]++;
}
int u=0,p;
for(int i=1;i<=ComponentNumber;i++)
{
if(!out[i]){u++;p=i;}
}
if(u>1)printf("0\n");
else printf("%d\n",Component[p].size());
}
return 0;
}