拓撲排序演算法及應用詳解1(原理與模板)

2021-09-29 19:24:36 字數 2730 閱讀 5397

排序是確定某序列的順序,之前我們學過很多的排序,他們基本上是對陣列進行排序,意在把一組元素序列按照某種自定義的順序進行排序(廣義)。它們的特點是,被排序的序列的元素之間存在某種大小關係,這種大小關係我們可以用數學意義上的**「大於」「小於」來體現。但是如果這種「大小關係」**我們不能用數學邏輯裡的:』>』 和 『

舉個最直觀的例子:我們在安排大學四年的上課順序的時候,每一門課,都有它的先修課和後續繼續深入的課,就像是上**設計之前要學一些程式語言和技巧,例如c/c++/sql,這樣才有利於php和mysql的學習,學**設計之後還要深入學習web系統設計。在這個關係種我們可以建立有向圖,先修課將指向後繼課程!所以大家可以想到,我們的拓撲排序是針對有向圖的,但是光是有向圖其實不夠,還必須是有向無環圖,從抽象的角度去理解,可以這麼認為,如果有環,那那個環中的元素,到底誰先誰後是不清楚的,後面我會用**來告訴大家,其實如果有環,那個環根本無法被處理!

我們不妨以這個為例,我們可以看到,這是乙個有向無環圖!

還是看之前的上課安排的例子,什麼課會第乙個被安排??很明顯,最基礎的課會被先安排,那什麼課是最基礎的呢?就是沒有先修課的課!那這個沒有先修課,就可以理解為當前有向無環圖的點,它的入度為0!在上面這個圖種我們很容易看到,有兩個入度為0的點:v1、v6,演算法步驟如下:

第一步:

度為0的點:v1 v6入佇列;

佇列狀態:v1、v6;

第二步:v1出佇列,v1直接指向的點:v2、v3、v4入佇列

佇列狀態:v6、v2、v3、v4;

第三步:v6出佇列,v6直接指向的點:v5入佇列

佇列狀態:v2、v3、v4、v5;

第四步:v2出佇列,v2直接指向的點:無入佇列

……接下來的步驟自己去模擬就好了,實際上大家可以看得出,這個拓撲排序我使用的是bfs的思想!

#include

#include

using

namespace std;

const

int maxn =

1e4+5;

vector<

int> g[maxn]

;int n, m, u, v, in[maxn]

, q[maxn]

;//陣列模擬佇列

intsort()

while

(l < r)

}// l < r 相當於佇列不空

return r;

// 檢查是否存在環路!

}int

main()

int cnt =

sort()

;if(n == cnt)

else

cout <<

"it is a circle!"

;return0;

}

值得注意的是:我這裡用陣列來模擬佇列操作,然後用鄰接表來存圖。用陣列是因為stl提供的佇列很容易爆(類內開闢空間不是在自由區開闢的,不能開那麼大),其實我這樣寫也還是很容易爆,在競賽種最好還是用迴圈佇列模擬、並且用鏈式前向星來存圖,這裡我只是為了來描述拓撲排序,於是就不搞那麼複雜了!

回顧dfs的特點:沿著一條可行路徑,一直搜素到最底層,然後逐層回溯,這個過程實際上正好反映了點與點之間的先後關係,天然符合拓撲排序!

演算法分析

在乙個有向無環圖種,如果有乙個點u,它的入度是0,那麼我們就從這個點開始做dfs。dfs返回的順序恰好就是乙個拓撲序!

處理一些細節

我們應該是以入度為0的點為dfs的開始,那我們該如何找到這個點?如果有很多入度為0的點,我們要乙個個去做dfs嗎?有這麼一種方法可以解決這個問題,我們可以假設乙個虛擬的點,這個點是圖中唯一乙個入度為0的點,圖中其他的所有點都是它的下一層遞迴!然而在實際程式設計的時候是不需要考慮這個點的,我們只需要在main()函式中把每乙個點輪流執行一遍dfs就可以了!這樣做就相當於顯式地遞迴了虛擬假象點的下一層點!

#include

#include

#include

#include

#include

using

namespace std;

const

int maxn =

1e4+5;

vector<

int> g[maxn]

;stack<

int> s;

int n, m, u, v, vis[maxn]

;bool

dfs(

int pos)

vis[pos]=1

;// 表示成功被處理

s.push

(pos)

;return

true;}

bool

sort()

return

true;}

intmain()

if(!sort()

) cout <<

"it has a circle!"

;else

}return0;

}

拓撲排序 kahn演算法及dfs的拓撲排序

有個人的家族很大,輩分關係很混亂,請你幫整理一下這種關係。給出每個人的孩子的資訊。輸出乙個序列,使得每個人的後輩都比那個人後列出 sample input 5 0 4 5 1 0 1 0 5 3 0 3 0樣例輸出 sample output 2 4 5 3 1 因為需輸出字典序最小的因而要使用優先...

拓撲排序的原理與實現

拓撲排序顧名思義是一種排序演算法,它用於給有向圖排序。有向圖是由一組頂點和一組有方向的邊組成的圖,每條有方向的邊都連線著有序的一對頂點,因此a b代表a可以到達b,並不代表b就能到達a。拓撲排序的結果就是乙個有向圖的頂點序列 或稱為拓撲序列 想要學習 c 程式設計 就需要先學習 計算機導論 想要學習...

tarjan演算法與拓撲排序

tarjan演算法要求使有向圖。tarjan就是乙個輔助作用,把有環圖縮為無環圖,也就是將強聯通分量縮成乙個點。對於每乙個節點,我們用dfn i 記錄它的時間戳,用low i 記錄它的回溯值 即不經過流圖搜尋樹上該節點父親能返回的最小的時間戳 dag縮點後的陣列,ins是否在棧中。樹邊 dfs孩子,...