题目地址:
https://www.acwing.com/problem/content/description/2718/
现在给你 n n n个物种和 m m m条能量流动关系,求其中的食物链条数。物种的名称为从 1 1 1到 n n n编号。 m m m条能量流动关系形如 a i b i a_i\ b_i ai bi,其中 a i b i a_i\ b_i ai bi表示能量从物种 a i a_i ai流向物种 b i b_i bi,注意单独的一种孤立生物不算一条食物链。
输入格式:
第一行两个整数
n
n
n和
m
m
m。
接下来
m
m
m行每行两个整数
a
i
,
b
i
a_i,b_i
ai,bi描述
m
m
m条能量流动关系。
数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现。
输出格式:
一个整数,即食物网中的食物链条数。
数据范围:
1
≤
n
≤
1
0
5
1≤n≤10^5
1≤n≤105,
0
≤
m
≤
2
×
1
0
5
0≤m≤2×10^5
0≤m≤2×105,
保证答案在int范围内。
先拓扑排序,求出以 i i i为结尾的食物链的条数 f ( i ) f(i) f(i)(单独一个物种也算食物链),那么对于那些出度为 0 0 0且入度不为 0 0 0的点累加 f f f值即可。代码如下:
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
int n, m;
int h[N], e[M], ne[M], idx;
int ind[N], outd[N];
int f[N];
bool is_end[N];
#define add(a, b) e[idx] = b, ne[idx] = h[a], h[a] = idx++
int bfs() {
queue<int> q;
for (int i = 1; i <= n; i++)
if (!ind[i]) {
q.push(i);
f[i] = 1;
} else if (!outd[i])
is_end[i] = true;
int res = 0;
while (q.size()) {
auto t = q.front();
q.pop();
if (is_end[t]) res += f[t];
for (int i = h[t]; ~i; i = ne[i]) {
int v = e[i];
f[v] += f[t];
if (!--ind[v]) q.push(v);
}
}
return res;
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
ind[b]++, outd[a]++;
}
printf("%d\n", bfs());
}
时间复杂度 O ( n + m ) O(n+m) O(n+m),空间 O ( n ) O(n) O(n)。