题目描述
如图所示为某生态系统的食物网示意图,据图回答第1小题.
![]()
1.数一数,在这个食物网中有几条食物链( )
现在给你n个物种和m条能量流动关系,求其中的食物链条数。
物种的名称为从1到n编号
M条能量流动关系形如
a1 b1
a2 b2
a3 b3
……
am-1 bm-1
am bm
其中 ai bi 表示能量从物种ai 流向物种bi
输入
第一行两个整数n 和 m。
接下来m行每行两个整数ai bi描述m条能量流动关系。
(数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现)
输出
一个整数即食物网中的食物链条数。
样例输入
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的那个图
各个物种的编号依次为
草 1兔 2狐 3鼠 4猫头鹰 5吃虫的鸟 6蜘蛛 7蛇 8青蛙 9食草昆虫 10
数据范围
1<=N<=100000 0<=m<=200000
题目保证答案不会爆int
思路
1e5的点2e5的边的有向图,邻接表存储;
从每一个生产者出发,DFS,直到终极消费者,为一条食物链;
记忆化,如果当前点后面有n条路,那么记录下来,以后再到这个点不必向下递归,直接调用;
注意:一个孤立的点并不是一条食物链!(PS:生物老师怎么说的来?食物链必须由生产者指向消费者,那么1条链至少有2个生物~)
Code
#include <bits/stdc++.h>
using namespace std;
const int mx = 200010;
struct node{
int to,next;
}edge[mx];
int m,n,tot,head[mx],a,b,ans;
int ss[mx];
bool vi[mx];
void add_edge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int p) {
if (head[p]==-1) {
ss[p]=1;
ans++;
return;
}
if (ss[p]) {
ans+=ss[p];
return;
}
for (int i=head[p];i!=-1;i=edge[i].next) {
//cout<<'i'<<i<<endl;
dfs(edge[i].to);
ss[p]+=ss[edge[i].to];
}
}
int main() {
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
while (m--) {
scanf("%d%d",&a,&b);
add_edge(a,b);
vi[b]=true;
}
for (int i=1;i<=n;++i)
if (!vi[i]&&(~head[i])) dfs(i);
printf("%d\n",ans);
return 0;
}