考点
DFS
题目描述
现在给你n个物种和m条能量流动关系,求其中的食物链条数。
物种的名称为从1到n的编号。 m条能量流动关系形如a b 表示能量从物种a 流向物种b。注意单独的一种孤立生物不算一条食物链。
此处的食物链指的是从生产者到当前链上最高级消费者的一条链。(入度为0出度为0的一条独立路径)
输入
第一行两个整数n和m,接下来 m行每行两个整数a b描述 m条能量流关系。
(保证输入数据符合生物学特点,且不会有重复的能量流动关系出现)
(1<=n<=100000 1<=m<=200000)
输出
一个整数,即食物网中的食物链条数。
输入样例
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
思路
For(生物 B in 生物A的后继)
以生物A开头的食物链数量 += 以生物B开头的食物链数量;
注意:单独的一种孤立生物不算一条食物链。因此我们要保存每个生物的入度和出度,对于出度入度都是0的就不计算
我们对每一个无入度而有出度的生物进行遍历
如果这个生物没有出度,这个食物链就到头了,以它开始的食物链只能有一条
如果我们已经访问过这个生物,就可以直接加上以这个生物开头的食物链数量
如果没有访问过这个生物,那么我们就可以遍历它后继的所有生物
代码
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 /*C4-Zexal的食物链*/ 6 using namespace std; 7 vector<int> g[100005]; 8 int n,m; 9 int in[100005], out[100005], vis[100005]; 10 11 int dfs(int x) 12 { 13 int tot = 0; 14 if(!out[x] && in[x]) return vis[x]=1;//出度为,以其开头只能有1个 15 if(vis[x]) return vis[x]; //判断是否记忆过,减少计算量 16 for(int i=0;i<g[x].size();i++) 17 { 18 tot += dfs(g[x][i]); //以生物A开头的食物链数量 += 以生物B开头的食物链数量; 19 } 20 vis[x] = tot; //记忆,减少计算量 21 return tot; 22 } 23 int main() 24 {25 int ans = 0; 26 cin>>n>>m; 27 for(int i = 0; i < m; i++) 28 { 29 int a,b; 30 cin>>a>>b; 31 g[a].push_back(b); 32 in[b]++; 33 out[a]++; 34 } 35 for(int i = 0; i < n; i++) //For(生物 B in 生物A的后继) 36 if(!in[i] && out[i]) //只计算入度为0 37 ans += dfs(i); //以生物A开头的食物链数量 += 以生物B开头的食物链数量; 38 cout<<ans<<endl; 39 return 0; 40 }