image

导读 ^ _ ^

拓扑序列,简单来说,就是将工程流程一步步输出来。很简单,这一步轮到他,那么它前面一定没有其他任务,也就是入度为0。故选出入度为0的点,就是实现拓扑排序的关键。

何为拓扑序列

  • 有向无环图又称为拓扑图
  • 是BFS的经典运用
  • 拓扑序:在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。
  • 有向无环图(DAG)一定有拓扑序列,有向有环图一定没有拓扑序列。
  • 出度:从节点出发,有几条边。 出度为零,表示是叶子节点。
  • 入度:进入节点,有几条边。 入度为零,表示是根,应该排在拓扑序列最前面的位置。

image.png

思路

把入度为0的点放入队列,输出,对其子节点入度减少一

代码实现

技巧:手写队列,这样队列序列就是topsort序列

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>

//复杂度 O(n+m)
using namespace std;

const int N = 100010, M = N*2;

int n, m;  //点数,边数
int h[N], e[M], ne[M], idx; //邻接表
int d[N]; // d[N]:入度,所有入度为零的点,可以排在当前最前面的位置。

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

int q[N]; //队列以及拓扑序列
bool topsort( ) {
    int hh = 0, tt = -1;
    for(int i = 1; i <=n; i++) 
       if(!d[i]) q[++tt] = i;
    while(hh <= tt) {
        int t = q[hh++];
        for(int i = h[t]; i != -1; i = ne[i]) {
            int j = e[i];
            if(--d[j] == 0) q[++tt] = j; 
        }
    }
    return tt == n-1;
}

int main( ) {
    memset(h, -1,sizeof h);
    cin >> n >> m;
    for(int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        add(a,b);
        d[b]++;
    }
    if (!topsort()) puts("-1");
    else {
        //队列次序其实就是拓扑序,这里就充分体现了利用数组模拟队列的优势,queue<int>就麻烦了。
        for (int i = 0; i < n; i++) printf("%d ", q[i]);
        puts(""); //有向无环图的拓扑序是不唯一的
    }
    return 0;
}

#谢谢你的观看!

^ _ ^