今天,我們來聊聊拓撲排序。
拓撲排序,這個顧名思義似乎有點難。那就直接上定義吧:
啥意思呢。比如這樣乙個dag:
幾種可能的拓撲序是:
也就是說,dag的拓撲序可能並不唯一。
那麼,1 3 2 4 5 6 7是不是這張圖的拓撲序呢?答案是否定的,因為圖中存在 \(2 \rightarrow 3\) 這條邊,那麼2必須出現在3的前面,但是這裡2卻出現在3的後面,因此不是拓撲序。
現在,你對拓撲排序的理解一定加深了一些。那麼接下來讓我們思考乙個問題,拓撲排序為什麼一定要在dag上?不在dag上難道不行嗎?
首先,dag是有向無環圖的意思,我們從有向和無環兩個方面分別做反義詞,也就是無向,有環。
接下來我們證明為什麼這兩種情況不能出現。
假設存在有無向邊的有 \(n\) 個點的圖 \(g\) 的拓撲序 \(a\),那麼一定存在兩個數 \(i, j (1 \le i, j \le n)\),滿足 \(a_i \rightarrow a_j \in g, a_j \rightarrow a_i \in g\)。根據拓撲序的定義,就有 \(i < j\) 且 \(i > j\),顯然不存在 \(i, j\) 滿足此邏輯關係,即有無向邊的圖無拓撲序。
假設存在有環的有 \(n\) 個點的圖 \(g\) 的拓撲序 \(a\),那麼一定存在 \(k(1 < k \le n), p(1 \le p \le n - k)\) 使得 \(a_ \rightarrow a_, a_ \rightarrow a_, a_ \rightarrow a_, \ldots, a_ \rightarrow a_, a_ \rightarrow a_ \in g\)。根據拓撲序的定義,就有 \(p + k < p + 1\),但 \(k > 1\),因此 \(p + k < p + 1\) 不可被滿足,即有環圖無拓撲序。
其實,無向邊可以看做包含兩個點的環,所以他們的證明很相似。
至此證畢。
眾所周知,dfs可以解決任何乙個不帶時限的題目(
那麼我們就來想下怎麼用dfs實現拓撲排序吧。
接下來是dfs函式處理步驟:
核心**如下:
int flag[maxn];
std :: vector topo;
std :: vector g[maxn];
int n, m;
bool dfs(int u)
}flag[u] = 1;
topo.push_back(u);
return true;
}bool toposort()
}std :: reverse(topo.begin(), topo.end());
return true;
}
kahn演算法有時候也叫做toposort的bfs版本。
演算法流程如下:
也就是說,kahn演算法的核心就是維護乙個入度為0的頂點。
核心**如下:
int ind[maxn];
bool toposort()
while (!q.empty())
}if (topo.size() == n) return true;
return false;
}
kahn演算法和dfs演算法的時間複雜度都為 \(\operatorname(e+v)\)。感興趣的讀者可以自證,這裡不再詳細闡述。
另外,如果要求字典序最小或最大的拓撲序,只需要將kahn演算法中的q佇列替換為優先佇列即可,總時間複雜度為 \(\operatorname(e+v\log v)\)。
說了這麼半天,拓撲排序有什麼用途嗎?
處理依賴性任務規劃問題的模板是uva10305,可以做做看。
本篇文章至此結束。
拓撲排序學習筆記
1.拓撲排序只對於有向無環圖而言 directed acyclic graph簡稱dag 2.在乙個有向無環圖中,若a b c,則拓撲序列為 a,b,c 也就是說如果一條邊a b,那麼在拓撲序列裡a就在b前面 知道了這兩點,那麼就可以來求拓撲序列了 首先,我們知道在dag中一定存在乙個入度為0的點,...
拓撲排序學習筆記
1.輸出字典序最小的拓撲序 在bfs演算法方法中用優先佇列 2.題意 n個點m條邊 dag 求刪去每個點後1 n最短路 n,m 3e5 做法 首先在dag中可以跑拓撲排序,跑完拓撲排序有什麼好處呢?拓撲序上的乙個點k作為劃分線,前半段的點的集合設為x,後半段點的集合設為y,那麼從點1到x中的任意乙個...
學習筆記 拓撲排序
有向圖的拓撲序列 給定乙個n個點m條邊的有向圖,點的編號是1到n,圖中可能存在重邊和自環。請輸出任意乙個該有向圖的拓撲序列,如果拓撲序列不存在,則輸出 1。若乙個由圖中所有點構成的序列a滿足 對於圖中的每條邊 x,y x在a中都出現在y之前,則稱a是該圖的乙個拓撲序列。輸入格式 第一行包含兩個整數n...