https://www.luogu.com.cn/problem/P4017
题意
有向图,找到其中,有且仅有 一个入度为0,出度为0的子图,求此图中满足条件的子图的个数。
解析
入度为0,出度为0,考虑拓扑排序。
求子图的个数考虑动态规划。
假设ABC能到达D,那么从D出发的总方案数是ABC之和。
我们按照拓扑排序的顺序来进行dp。
整体来看:在每一个子图之中,最后一个点一定是出度为0的点,即我们拓扑排序的终点,因此保证了动态规划的顺序。
再考虑每个点:我们按照拓扑排序的顺序,在我们队列中的元素入度都是为0,也就是说,其他能到达队列中的元素的点已经被遍历过了,因此保证动态规划的顺序不会出错。
代码
#include<bits/stdc++.h>
using namespace std;
const int mod=80112002;
int n, m, h[5005], ru[5005], chu[5005], f[5005], ans;
struct AB{
int a,b,n;
}d[5000005];
queue<int> q;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int a, b;
scanf("%d%d", &a, &b);
d[i].a=a, d[i].b=b, d[i].n=h[a], h[a]=i;//建图
chu[a]++, ru[b]++;
}
for(int i=1;i<=n;i++){
if(ru[i]==0) {
f[i]=1;
q.push(i);
}
}
while(!q.empty()){
int a=q.front();
q.pop();
for(int k=h[a];k;k=d[k].n){
int b=d[k].b;
f[b]+=f[a];
f[b]%=mod;
ru[b]--;
if(ru[b]==0){
if(chu[b]==0){
ans+=f[b];
ans%=mod;
}//出度为0的点为食物链终点,记录答案,并且不必入队
else q.push(b);
}
}
}
cout<<ans;
}