题目
如图所示为某生态系统的食物网示意图,据图回答此题。
现在给你 n 个物种和 m 条能量流动关系,求其中的食物链条数。
物种的名称为从 1 到 n 的编号。
mm 条能量流动关系形如
a1 b1
a2 b2
a3 b3
…
am bm
其中 ai bi 表示能量从物种 ai 流向物种 bi。注意单独的一种孤立生物不算一条食物链。
输入格式
第一行两个整数 n 和 m,接下来 m 行每行两个整数 ai bi 描述 m 条能量流动关系。
(保证输入数据符合生物学特点,且不会有重复的能量流动关系出现)
[tips:应该是指没有环,也没有重边]
输出格式
一个整数,即食物网中的食物链条数。
样例
Input | Output |
---|---|
10 16 1 2 1 4 1 10 2 3 2 5 4 3 4 5 4 8 6 5 7 6 7 9 8 5 9 8 10 6 10 7 10 9 | 9 |
数据范围与提示
2000001≤N≤100000,0≤m≤200000
保证答案不会超过 int
的最大值
思路
运用拓扑排序的思想,没有入度的顶点就是一条食物链的最底层,没有出度的顶点则是最高层,使用邻接表来实现。
统计有多少条食物链就相当于寻找有多少条从入度为0到出度为0的边
代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
queue<int>q;
vector<int>v[100005];
int n, m, a[100005], b[100005], c[100005], ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int x, y;
cin >> x >> y;
v[x].push_back(y);
++a[x], ++b[y];
}
for (int i = 1; i < n; ++i)
{
if (a[i] && !b[i])
{
c[i] = 1;
q.push(i);
}
}
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = 0; i < v[t].size(); ++i)
{
int p = v[t][i];
c[p] += c[t];
--b[p];
if (!b[p])
{
q.push(p);
}
}
}
ans = 0;
for (int i = 1; i <= n; ++i)
{
if (!a[i])
{
ans += c[i];
}
}
cout << ans;
return 0;
}