每头奶牛都不想成为被新型病毒感染的奶牛。被所有奶牛接触的奶牛就是一头被感染的奶牛。因为奶牛喜欢偷偷摸摸地行动,所有接触是单向的,所有奶牛都与自己接触。奶牛之间的接触是可以传递的——如果 $A$ 接触过 $B$ ,$B$ 接触过 $C$ ,那么 $A$ 也接触过 $C$ 。牛栏里共有 $N$ 头奶牛,给定一些奶牛之间的接触关系,请你算出有多少头奶牛不幸被感染。 输入的第一行是两个用空格分开的整数 $N$ 和 $M$ 。接下来 $M$ 行每行两个用空格分开的整数 $A$ 和 $B$ ,表示 $A$ 接触过 $B$ 。输出被感染的奶牛的数量。
提示:考虑将接触关系建图,强连通缩点,然后进行接下来的操作。
#include<bits/stdc++.h>
using namespace std;
struct edge {
int v, next;
} p[50001];
int front[10001], M;
void Add(int u, int v) {
++M;
p[M].v = v;
___(1)___;
front[u] = M;
}
int dfn[10001], low[10001], N, s;
stack <int> zhan;
int which[10001];
int Out[10001], id, large[10001];
int n, m;
int dfs(int x) {
++N;
dfn[x] = low[x] = N;
zhan.push(x);
for (int i = front[x]; i; i = p[i].next) {
if (___(2)___) {
dfs(p[i].v);
___(3)___;
} else
low[x] = min(low[x], dfn[p[i].v]);
}
if (dfn[x] == low[x]) {
++s;
int S = 0;
int v;
do {
v = zhan.top();
zhan.pop();
___(4)___;
++S;
} while (x != v);
Large[s] = S;
}
}
int main() {
int i, j;
scanf("%d%d", & n, & m);
for (i = 1; i <= m; ++i) {
int x, y;
scanf("%d%d", &x, &y);
Add(x, y);
}
for (i = 1; i <= n; ++i)
if (dfn[i] == 0) dfs(i);
for (i = 1; i <= n; ++i)
for (j = front[i]; j; j = p[j].next)
if (which[p[j].v] != which[i])
___(5)___;
for (i = 1; i <= s; ++i)
if (Out[i] == 0) {
if (id != 0) {
printf("%d\n", 0);
return 0;
}
id = i;
}
printf("%d\n", large[id]);
return 0;
}
1. C。
2. A。
3. D。
4. B。
5. A。
Tarjan 缩点后,图为有向无环图。如果此时图中存在多个出度为 $0$ 的点,则没有被感染的奶牛,否则出度为 $0$ 的点为被感染的奶牛,输出该点内原本点的数量。