适用条件:无环图
输出结果:使得每个节点,以它为终点的起点节点排都在其前面
作用:递推保证前面的节点都已经被使用过
实现方法:从没有入边的节点开始,输出并从其他节点中删去自己,重复此步骤直到所有节点都被输出
图解:
算法实现:
1.记录节点的入边的个数
2.将入边个数为0的加入队列
3.从队列中取点,输出并删去该点,将以它为起点的节点的入边都减1,如果减为0就加入队列。
4.重复3步骤直到所有数均被输出
例题:洛谷P4017 最大食物链计数
思路:
到某个生物的可能食物链数量为它所有可吃的生物的可能食物链数量之和,但再此之前,那些可吃的生物的可能食物链数量必须已经被算出来,这时结合我们的拓扑排序就能解决这个问题
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5e3 + 10,MAXM = 5e5 + 10,MOD = 80112002;
int ptop = 1;
ll sum = 0,a[MAXN];
bool use[MAXN];
struct link{
int p;
link* nex;
}p[MAXM],q[MAXM];
link* head[MAXN],*qhead[MAXN];
void add(int x,int y)
{
p[ptop].nex = head[x];
p[ptop].p = y;
head[x] = &p[ptop];
q[ptop].nex = qhead[y];
q[ptop].p = x;
qhead[y] = &q[ptop];
ptop++;
}
int dad[MAXN];
int son[MAXN];
queue<int> qu;
void adddad(int x)
{
link* pp = head[x];
while(pp != NULL)
{
int y = pp -> p;
a[y] += a[x];
a[y] %= MOD;
son[y]--;
if(son[y] == 0)
qu.push(y);
pp = pp -> nex;
}
}
int main()
{
int n,m;cin >> n >> m;
for(int i = 1;i <= m;i++)
{
int x,y;scanf("%d %d",&x,&y);
add(x,y);
dad[x]++;
son[y]++;
}
for(int i = 1;i <= n;i++)
{
if(son[i] == 0)
{
a[i] = 1;
qu.push(i);
}
}
while(!qu.empty())
{
int x = qu.front();qu.pop();
adddad(x);
if(dad[x] == 0)
sum += a[x],sum %= MOD;
}
cout << sum;
}