拓撲排序
阿新 • • 發佈:2020-07-29
首先明白什麼是拓撲序列?
只有有向圖才會有拓撲序列,每一條邊的起點都在終點之前
例如:
但如果是這樣子的
有向圖中存在一個環 則它就不存在拓撲序列。
拓撲圖:有向無環圖一定存在拓撲序列,因此有向無環圖也叫做拓撲圖,所有入度為0的節點都可以作為起點,因此拓撲序列並不唯一。**
有向無環圖一定存在拓撲序列是因為,一定至少存在一個入度為0的點,因此可以逐個突破,生成拓撲序,而一個環上的每個點入度必不為0。
生成拓撲序列的步驟
queue <- 所有入度為0的點 while queue不為空 { t <- 取隊頭 列舉t所有出邊 t-j 刪掉t->j j入度減一:d[j]-- if(d[j] == 0) 說明節點j的入度為0 可以作為起點入隊 queue <- j 所有點全部入隊 拓撲序列排序完成 } 輸出拓撲序(在佇列中)
而且這個題體現出了用陣列模擬queue的好處,用佇列陣列儲存的正好是拓撲序
程式碼:
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 100010; int n, m; int h[N], e[N], ne[N], idx; int q[N], d[N]; //d用來存一個點的入度 bool torsort() { int hh = 0, tt = 0; for(int i = 1; i <= n; i++) //把入度數為0的節點全部入隊 { 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]; d[j]--; //刪出邊 if(d[j] == 0) q[++tt] = j; //入隊 } } return tt == n; //所有點都入隊 則完成拓撲序 } void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } int main() { memset(h, -1, sizeof h); scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); add(a, b); d[b]++; //入度加1 } if(torsort()) { for(int i = 1; i <= n; i++) printf("%d ", q[i]); puts(""); } else puts("-1"); system("pause"); return 0; }