题目:
如图所示为某生态系统的食物网示意图,据图回答此题。
现在给你 nn 个物种和 mm 条能量流动关系,求其中的食物链条数。
物种的名称为从 11 到 nn 的编号。
mm 条能量流动关系形如
a_1a1 b_1b1
a_2a2 b_2b2
a_3a3 b_3b3
… …
a_mam b_mbm
其中 a_i \ b_iai bi 表示能量从物种 a_iai 流向物种 b_ibi。注意单独的一种孤立生物不算一条食物链。
输入格式
第一行两个整数 nn 和 mm,接下来 mm 行每行两个整数 a_i \ b_iai bi 描述 mm 条能量流动关系。
(保证输入数据符合生物学特点,且不会有重复的能量流动关系出现)
[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 |
数据范围与提示
1 \leq N \leq 100000, 0 \leq m \leq 2000001≤N≤100000,0≤m≤200000
保证答案不会超过 int
的最大值
题解:拓扑排序(解决有优先级问题的问题) :我们在食物链中被吃就将出度+1,吃别人将入度+1。最终对于每种动物都得到其对应的入度与出度。我们进行一个while循环,直到所有动物的入度为0结束循环。每次循环,先找到入度为零的那一个点,将所有吃这个动物的那只动物的食物链数量加上该入度为0的动物的那点的食物链数量即可。
代码:
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <cstdio>
using namespace std;
vector <int> g[100001],q;
int n,m,a,b,f[100001],d=0,l=0,in[100001],out[100001],bb[100001];
int main()
{
cin >> n >> m;
for (int i=1;i<=n;i++) g[i].push_back(0);//我会忘记vector数组0开头,所以先垫个0
for (int i=1;i<=m;i++)
{
cin >> a >> b;
out[a]++;in[b]++;
g[a].push_back(b);//g[a]储存吃a的动物
bb[a]++;bb[b]++;//bb数组用来判断是否有不吃动物也不被吃的动物,单一动物不算食物链
}
for (int i=0;i<=n;i++)
{
q.push_back(i);//将所有动物放入数组中便于计算数量
if (out[i]==0) d++;//找出不被吃的动物的动物数量
if (in[i]==0) f[i]=1;//作为生产者(什么动物也不吃的那种动物)的食物链数量始定为1
}
d--;
while(q.size()-1!=d)//直到剩下的动物都不会被吃
{
for (int i=1;i<=q.size();i++)
if (in[q[i]]==0&&out[q[i]]!=0)//找到入度为0并且出度不为0的点(排除单一动物影响)
{
in[q[i]]--;
for (int j=1;j<=out[q[i]];j++)
{
in[g[q[i]][j]]--;//g[q[i]][j]是第q[i]个g中的第j个数据
f[g[q[i]][j]]=f[g[q[i]][j]]+f[q[i]];//食物链数量相加
}
q.erase(q.begin()+i,q.begin()+i+1);//在队列中清除生产者(什么动物也不吃的哪种动物)
break;
}
}
for (int i=1;i<=n;i++)
if (out[i]==0&&bb[i]!=0) l=l+f[i];//若出度为0并且非单一动物,计算食物链数量
cout << l;
}