P4017 最大食物链计数 (拓扑排序)
看到拓扑排序感觉非常遥远的复杂,不喜欢图。看了拓扑排序的原理,很像广搜。
以本题样例为例:
了解一下 出度 和 入度
5的出度为3 入度为 0 ,3的出度为2 入度为2……
for循环 找到秃头 5 入队列, 然后给跟他有联系的所有点一一剃头,看谁再秃,秃了入队列,再对继往开来的秃子进行操作。
#include<cstdio> #include<iostream> #include<queue> using namespace std; int n,m,ru[5050],chu[5050],f[5050],a,t,ans,b,s[5050][5050]; //ru[]是入度,chu[]是出度(后面判断是否为尾巴用的),f[i]代表到i点多少条路径, s[][]邻接矩阵存储两点之间是否有联系。 queue<int> q; int main() { scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); ru[a]++; chu[b]++; s[b][a]=1; } for(int i=1;i<=n;i++) { if(ru[i]==0)//寻找先天的秃子 { q.push(i); f[i]=1; } } while(true) { if(q.empty())break;//秃子队列没了,就结束了。 t=q.front();//找出队列前端的秃子,暂存到t里。 q.pop();// 没用了的秃子消失吧。 for(int i=1;i<=n;i++) { if(s[t][i]==1)//找到和秃子有联系的家伙,间断它们之间的烦恼丝 { f[i]+=f[t];//凡是和它有联系的都要把方案+上它(递推),不懂这一点的递推做一做过河卒 f[i]=f[i]%80112002; ru[i]--;//剪掉入度 if(ru[i]==0)//看看秃了没有 { if(chu[i]==0)//看看到尾巴了吗?如果没有出度了,说明没有了后续,等着干啥,统计一下吧。 { ans+=f[i];//因为可能有多个尾巴,所以这里要用+=。如果没有这个,就是单尾巴。 ans=ans%80112002; continue; } q.push(i);//剪秃了,入队列吧。 } } else { continue; } } } cout<<ans; return 0; }