|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 10010, M = 50010;
|
|
|
int n, m; // n个点,m条边
|
|
|
int d[N]; // 记录一下每个强连通分量的出度
|
|
|
|
|
|
// 链式前向星
|
|
|
int e[M], h[N], idx, w[M], ne[M];
|
|
|
void add(int a, int b, int c = 0) {
|
|
|
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
|
|
|
}
|
|
|
|
|
|
// Tarjan算法求强连通分量
|
|
|
int stk[N], top, in_stk[N]; // stk[N]:堆栈,top:配合堆栈使用的游标top,in_stk[N]:是否在栈内
|
|
|
int dfn[N], ts, low[N]; // dfn[N]:时间戳记录数组,ts:时间戳游标, low[N]:从u开始走所能遍历到的最小时间戳
|
|
|
int id[N], scc_cnt, sz[N]; // id[N]:强连通分量块的编号,scc_cnt:强连通分量的编号游标,sz[i]:编号为i的强连通分量中原来点的个数
|
|
|
|
|
|
void tarjan(int u) {
|
|
|
dfn[u] = low[u] = ++ts; // 初始时间戳
|
|
|
stk[++top] = u; // 入栈
|
|
|
in_stk[u] = 1; // 在栈内
|
|
|
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int v = e[i];
|
|
|
if (!dfn[v]) { // v未访问过
|
|
|
tarjan(v); // dfs深搜
|
|
|
low[u] = min(low[u], low[v]); // 更新low[u]
|
|
|
} else if (in_stk[v]) // v已经栈中,找到强连通分量
|
|
|
low[u] = min(low[u], dfn[v]); // 更新low[u]
|
|
|
}
|
|
|
// 发现强连通分量
|
|
|
if (dfn[u] == low[u]) {
|
|
|
++scc_cnt;
|
|
|
int x;
|
|
|
do {
|
|
|
x = stk[top--];
|
|
|
in_stk[x] = 0;
|
|
|
id[x] = scc_cnt; // 记录x是缩点后编号为ssc_cnt号强连通分量的一员
|
|
|
sz[scc_cnt]++; // 缩点后编号为ssc_cnt号强连通分量中的成员个数+1
|
|
|
} while (x != u);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
scanf("%d %d", &n, &m);
|
|
|
memset(h, -1, sizeof h); // 初始化邻接表
|
|
|
for (int i = 1; i <= m; i++) {
|
|
|
int a, b;
|
|
|
scanf("%d %d", &a, &b);
|
|
|
add(a, b);
|
|
|
}
|
|
|
//(1)求强连通分量,缩点
|
|
|
for (int i = 1; i <= n; i++) // 需示枚举每个点出发尝试,否则会出现有的点没有遍历到的情况
|
|
|
if (!dfn[i]) tarjan(i);
|
|
|
|
|
|
//(2)缩点后其实就是一个DAG,计算出DAG中每个新节点的出度
|
|
|
for (int u = 1; u <= n; u++) // 枚举原图中每个出边,用法好怪异~
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int v = e[i]; // u->v
|
|
|
int a = id[u], b = id[v]; // u,v分别在哪个强连通分量中
|
|
|
if (a != b) d[a]++; // a号强连通分量,也可以理解为是缩点后的点号,出度++
|
|
|
}
|
|
|
|
|
|
//(3) 出度为0的只能有1个,如果大于1个,就无解,如果正好是一个,返回此强连通分量中结点的个数
|
|
|
int zeros = 0, res = 0;
|
|
|
for (int i = 1; i <= scc_cnt; i++) // 枚举强连通分量块
|
|
|
if (!d[i]) { // 如果出度是0
|
|
|
zeros++; // 出度是0的强连通分量个数+1
|
|
|
res = sz[i]; // 累加此强连通分量中点的个数
|
|
|
if (zeros > 1) { // 如果强连通分量块的数量大于1个,则无解
|
|
|
res = 0;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//(4)求有多少头牛被除自己之外的所有牛认为是受欢迎的
|
|
|
printf("%d\n", res);
|
|
|
return 0;
|
|
|
}
|