首先先讲一下拓扑排序的递归做法。
看似有点玄学,讲一下为什么是正确的,在一张拓扑图,我们如果能够保证每一条边 a−−−>ba ---> ba−−−>b,在序列中aaa 始终保证在bbb 的前边,那么这个序列一定是拓扑序。贴一下dfsdfsdfs求拓扑的代码:
bool dfs(int x)
{
vis[x] = true, st[x]= true; //st 数组表示的是点是否遍历到,vis数组则表达的是点是否在正在搜索 dfs 路径上。seq 倒序输出就是答案
for (int i = h[x]; i != -1; i = ne[i])
{
int j = e[i];
if (vis[j]) return false;
if (st[j]) continue;
if (!dfs(j)) return false;
}
seq[cnt ++] = x;
vis[x] = false;
return true;
}
我们在遍历的时候假设之前bbb没有遍历到,那么我们的bbb 一定是在aaa 前边的,如果是已经遍历过了,那么bbb也是在aaa前边,在倒序的输出下就变成了aaa在bbb的前边,这里可以简单的思考下。
根据这个算法的启发,我们的tarjantarjantarjan算法的目的是将一个有向图转变成一个有向无环图,也就相当于拓扑图,tarjantarjantarjan算法需要处理横叉边和后向边。我们将tarjan算法的极大连通图看成一个点,那么这个过程实际上跟递归求拓扑序是一样的,所以得出一个结论就是我们在算tarjan算法的时候就相当于已经做了一遍拓扑排序,所以不需要在做一遍(虽然求拓扑时间复杂度是线性的),只需要倒序就是拓扑序,分析和上边是一样的。