题目链接
题目思路
显然可以用记忆化搜索来做,但这个题目要我了解一下拓扑排序。但感觉拓扑排序好像没什么用
拓扑排序
在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。
先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
一直做改操作,直到所有的节点都被分离出来。
如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
下面是算法的演示过程。
题目分析
这里具体讲一下为什么要用拓扑排序(思维过程):
1、这是一道图论题
2、不是求最短路
3、根据提示“最左端是不会捕食其他生物的生产者”可以想到,我们要入度为零的点开始查找
4、再看一遍题目,就是求路径数,当且仅当一个点的入度变为零时才需要入队,并不是数据更新一次就要入队
5、出度为零的点的路径总数和就是答案
f [ i ]表示到达i的路径数量
代码
#include<queue>
#include<cstdio>
using namespace std;
const int maxn=5e3+5;
const int mod=80112002;
int n,m,head[maxn],chu[maxn],ru[maxn],f[maxn],cnt,ans,u,v;
queue<int> q;
struct node{
int to,next;
}e[maxn*100];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
add(v,u);
chu[v]++,ru[u]++;
}
for(int i=1;i<=n;i++){
if(!ru[i]){
f[i]=1;
q.push(i);
}
}
while(!q.empty()){
int fa=q.front();
q.pop();
for(int i=head[fa];i;i=e[i].next){
int son=e[i].to;
f[son]=(f[son]+f[fa])%mod;
ru[son]--;
if(!ru[son]){
if(chu[son]){//还要继续
q.push(son);
}else{//已经是生产者了
ans=(ans+f[son])%mod;
}
}
}
}
printf("%d\n",ans);
return 0;
}
参考文章
https://blog.csdn.net/qq_41713256/article/details/80805338
https://www.luogu.com.cn/blog/dbyblog/solution-p4017