..食物链

题目:

如图所示为某生态系统的食物网示意图,据图回答此题。

现在给你 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:应该是指没有环,也没有重边]

输出格式

一个整数,即食物网中的食物链条数。

样例

InputOutput
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值