1. 程式人生 > 其它 >演算法專題——拓撲排序

演算法專題——拓撲排序

拓撲排序

拓撲序的概念

將節點的編號按照序列的形式排開,則我們將前面節點總是指向後面節點,後面節點不會指向前面節點的序列稱為拓撲序列。並將可以得到拓撲序列的圖稱為拓撲圖。如上圖,就是一個拓撲圖,可以得到拓撲序,123

拓撲圖的幾個性質

  1. 拓撲圖總是有向無環圖。有環圖得不到拓撲序。有向無環圖總是可以得到入度為0的節點,. 依據這一點可以得到拓撲序
  2. 拓撲圖可以看為由若干指向相同的連結串列黏連而成的, 拓撲圖中入度為0的點為連結串列的起點, 出度為0的點為連結串列的終點.


求拓撲序

藉助拓撲序總是可以找到入度為0的點的性質, 我們只要總是將入度為0的點彈出即可得到拓撲序, 於是我們可以通過BFS實現, 見虛擬碼

for (所有點) 
	if (入度為0) 入隊que
while(que非空) {
	得到對頭u
	for (與u相連的點) {
		與u相連的點的入度--;
		if (如果該點入度減為為0) 入隊que
	}
}	



拓撲序的特點

拓撲圖可以看為由若干指向相同的連結串列黏連而成的, 因此具有非常好的性質, 以及特點.

拓撲序對於處理dp具有天然的優勢, 所以可以按照拓撲序的方法對拓撲圖進行dp遞推, 進而也可以處理最短/長路問題, 時間複雜度可以減到線性.

拓撲圖固定的知識點不多, 但有一些零零碎碎的二級結論不少, 可能會作為題目的一環讓選手手推結論. 具體的可以看例題.



例題

三道題與強連通分量結合的題, 見部落格演算法專題——強連通分量
.


可達性統計

題面:

分析:

基本可以轉移到dp的做法, 每一個節點記錄可以訪問到的節點分別是什麼, 轉移的時候進行處理.

可以用bitset儲存所含的節點, 也剛好不會超時, 結合拓撲dp即可接出來. 見下面核心程式碼.



車站分級

題面:

分析:

可以發現停靠站和非停靠站之間具有某些特殊的關係, 即非停靠站的等級大小一定都小於停靠站的等級大小. 於是問題就變得和差分約束差不多了, 但是如果用傳統的建圖方式會有些問題, 可以發現非停靠站的每一個站點的等級由於小於停靠站每一個站點的等級, 所以總共需要連線非停靠站站點數量 * 停靠站站點數量條邊, 最壞的情況下, 需要連線車次 * 停靠站 * 非停靠站 == 1000 * 500 * 500 == 2.5 * 10 ^ 8

條邊, 時空複雜度都會爆掉. (下為一個車次需要建的邊, 沒有畫出邊的方向, 實際上是有的, 方向均為非停靠站指向停靠站)

所以需要改變一下建圖的方法, 可以引入一個虛擬原點, 見下圖, 可以設定非停靠站指向虛擬原點的邊的邊權為0, 虛擬原點指向停靠站的邊的邊權為1, 這樣建出的圖的效果與上面是一樣的, 但是需要的空間卻少了很多, 變成了非停靠站站點數量 + 停靠站站點數量條邊.

剩下的就是普通的差分約束了, 核心程式碼見下.