# [HAOI2016]食物链
## 题目描述
如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数。物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3......am-1 bm-1am bm其中ai bi表示能量从物种ai流向物种bi,注意单独的一种孤立生物不算一条食物链
## 输入格式
第一行两个整数n和m,接下来m行每行两个整数ai bi描述m条能量流动关系。(数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现)1<=N<=100000 0<=m<=200000题目保证答案不会爆 int
## 输出格式
一个整数即食物网中的食物链条数
## 样例 #1
### 样例输入 #1
```
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
```
### 样例输出 #1
```
9
```
记忆化搜索:
从入度为0的点开始往下面节点搜索(切记入读为0并且出度为0是个单独的节点pass掉),直到搜索到出度为0的节点,返回1,途中记录每个节点是否被搜索遍历过,如果被遍历过,直接返回权值即可。
从入读为零的点进行记忆化搜索,搜到出度为零的点返回1
所有返回值加起来就是答案。
#include<bits/stdc++.h>
using namespace std;
struct node {
int u,v,next;
} e[200010];
int st[1000010];
int out[1000010];
int ind[1000010];
int f[1000010];
int n,m,a,b,ans,tot,s,end;
void add(int x,int y) {
e[++tot].u=x;
e[tot].v=y;
e[tot].next=st[x];
st[x]=tot;
}
int dfs(int x) {
if(f[x])return f[x];//如果之前记录过该点有几条到达过他的方案
int ans=0;
if(out[x]==0)return 1;//到达了初读为0的地方,也就是到达了最后
for(int i=st[x]; i; i=e[i].next) {
ans+=dfs(e[i].v);
}
f[x]=ans;//记忆化,x可以有几条食物链
return ans;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++) {
scanf("%d%d",&a,&b);
add(a,b);
out[a]++;//a的初读+1
ind[b]++;//b的入读+1
}
for(int i=1; i<=n; i++) {
if(ind[i]==0&&out[i]!=0) {
//入读为0出度不为0
ans+=dfs(i);
}
}
cout<<ans;
}
拓扑排序 :我们记录入度为0并且出度不为0的点方案书为1,然后直接裸toposort,最后的答案就是所有加入队列的出度为0的点
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int N=2e6+5;
int rd[N];
int n,m,f[N];
vector<int>e[N];//邻接矩阵存储,速度慢于上面的链式前向星存储结构
int toposort() {
queue<int>q;
int ans=0;
for(int i=1; i<=n; i++) {
if(!rd[i]&&e[i].size()) { //入读为0并且出度不为0
q.push(i);
f[i]=1;
}
}
while(!q.empty()) {
int x=q.front();
q.pop();
if(!e[x].size())//出度为0
ans+=f[x];
for(auto t: e[x]) {
f[t]+=f[x],rd[t]--;
if(!rd[t]) { //入读为0了
q.push(t);
}
}
}
return ans;
}
int main() {
cin>>n>>m;
for(int i=1,x,y; i<=m; i++) {
cin>>x>>y;
rd[y]++;
e[x].push_back(y);
}
cout<<toposort();
}