一、什么是拓撲排序
在圖論中,拓撲排序(Topological Sorting)是一個有向無環圖(DAG, Directed Acyclic Graph)的所有頂點的線性序列。且該序列必須滿足下面兩個條件:
每個頂點出現且只出現一次。
若存在一條從頂點 A 到頂點 B 的路徑,那么在序列中頂點 A 出現在頂點 B 的前面。
有向無環圖(DAG)才有拓撲排序,非DAG圖沒有拓撲排序一說。
例如,下面這個圖:
它是一個 DAG 圖,那么如何寫出它的拓撲排序呢?這里說一種比較常用的方法:
1:從 DAG 圖中選擇一個 沒有前驅(即入度為0)的頂點並輸出。
2:從圖中刪除該頂點和所有以它為起點的有向邊。
3:重復 1 和 2 直到當前的 DAG 圖為空或當前圖中不存在無前驅的頂點為止。后一種情況說明有向圖中必然存在環。
於是,得到拓撲排序后的結果是 { 1, 2, 4, 3, 5 }。
通常,一個有向無環圖可以有一個或多個拓撲排序序列。
二、拓撲排序的應用
拓撲排序通常用來“排序”具有依賴關系的任務。
比如,如果用一個DAG圖來表示一個工程,其中每個頂點表示工程中的一個任務,用有向邊<A,B><A,B>表示在做任務 B 之前必須先完成任務 A。故在這個工程中,任意兩個任務要么具有確定的先后關系,要么是沒有關系,絕對不存在互相矛盾的關系(即環路)。
三 題目:
給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環。
請輸出任意一個該有向圖的拓撲序列,如果拓撲序列不存在,則輸出-1。
若一個由圖中所有點構成的序列A滿足:對於圖中的每條邊(x, y),x在A中都出現在y之前,則稱A是該圖的一個拓撲序列。
輸入格式
第一行包含兩個整數n和m
接下來m行,每行包含兩個整數x和y,表示存在一條從點x到點y的有向邊(x, y)。
輸出格式
共一行,如果存在拓撲序列,則輸出拓撲序列。
否則輸出-1。
數據范圍
1≤n,m≤1051≤n,m≤105
輸入樣例:
3 3
1 2
2 3
1 3
輸出樣例:
1 2 3
############################################

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e5+10; 5 vector<int> h(N,-1), e(N,-1), ne(N,0); 6 int idx; 7 int q[N],hh = 0, tt = -1;//模擬隊列 8 int d[N];//入度 9 int n, m; 10 11 void add(int a, int b){ 12 e[idx] = b; 13 ne[idx] = h[a]; 14 h[a] = idx ++; 15 } 16 17 bool topsort(){ 18 for(int i = 1;i <= n;++i) 19 if(d[i] == 0) q[++tt] = i; 20 while(hh <= tt){ 21 int t = q[hh++]; 22 for(int i = h[t];i != -1;i = ne[i]){ 23 int tmp = e[i]; 24 -- d[tmp]; 25 if(d[tmp] == 0) q[++tt] = tmp; 26 } 27 } 28 return tt == n-1; 29 } 30 31 int main(){ 32 cin >> n >> m; 33 for(int i = 0;i < m;++i){ 34 int a, b; 35 cin >> a >> b; 36 add(a, b); 37 d[b] ++; 38 } 39 if(topsort()){ 40 for(int i = 0;i < n;++i)cout << q[i] << " "; 41 }else cout << -1 << endl; 42 return 0; 43 }