演算法學習筆記 19 拓撲排序

2021-10-19 07:04:20 字數 1818 閱讀 3068

計算拓撲序列的乙個方式是,用bfs來嘗試訪問所有的節點,但是有乙個約束就是只有入度為0

00的節點才能被加入到擴充套件佇列裡。每次從佇列裡取出乙個節點,也就同時在圖中將這個節點拆除,所以它的所有後繼的節點都減少1

11,如果已經減少到0

00,那麼就可以加入到佇列中。

在上面的例子中,一開始只有a

aa的入度是0

00,所以先把a

aa加入到佇列中,佇列中:

a

aa然後取出隊頭a

aa並在圖中拆除,然後它的後繼c

cc的入度變成1

11,b

bb的入度變成0

00,把b

bb加入到佇列裡,佇列中:

b

bb然後取出隊頭b

bb並在圖中拆除,然後它的後繼c

cc和d

dd的入度都變成0

00,都加入到佇列裡,佇列中是:

c

dc~d

cd或者d

cd~c

dc接下來也是重複這個過程,最後得到拓撲序列是abc

da~b~c~d

abcd

或者a bd

ca~b~d~c

abdc

(取決於c

cc和d

dd哪個先從「d

dd的所有後繼」這個集合中訪問)。

在實現拓撲排序時,用模擬佇列來代替stl的佇列比較方便。一方面是,觀察上面的過程可以發現,只要所有節點都被加入到佇列裡了,那麼就能說明所有的節點都能被訪問,就說明存在拓撲序列。如果用模擬佇列,由於它的兩個指標一直往後移的特性,只要看一下隊尾指標tt是不是在n-1位置就能知道是不是這n個元素都加入過佇列中了。

另外,由於模擬佇列刪除元素只是做++hh的操作,而沒有破壞隊頭hh位置的元素取值,所以最後輸出拓撲序列的時候可以直接從0n-1遍歷一下佇列,輸出的就是拓撲序了。

#include

#include

using

namespace std;

const

int n =

1e5+10;

int n, m;

// 記錄每個節點的入度

int d[n]

;// 鄰接表

int h[n]

, e[n]

, ne[n]

, idx;

// 鄰接表新增有向邊

void

add_edge

(int a,

int b)

// 模擬佇列

int q[n]

, hh, tt =-1

;// 拓撲排序,如果存在拓撲序返回真

bool

topo_sort()

// bfs訪問過程

while

(hh <= tt)

}// 如果所有n個節點都加入過佇列,就存在拓撲序

return tt == n -1;

}int

main()

// 如果存在拓撲序,模擬佇列中依次入隊的順序就是拓撲序if(

topo_sort()

)else

return0;

}

演算法學習筆記(拓撲排序)

拓撲排序,在我現在看來,就是用來解決一系列分層次執行的問題。什麼意思呢?舉個例子 oi wiki上看到的 比如說我們大學生都要面臨選課問題,那麼某些課程會有一些先行課程,必須先修這些先行課程才能夠繼續修讀某課程,那麼現在問題來了,小明有n種課程需要選讀,n種課程之中,有一些課程有先後關係 也就是說修...

演算法學習 拓撲排序

相關例題 要理解拓撲排序,首先需要知道圖論的乙個基本概念 入度 有向圖中某點作為圖中邊的終點的次數之和 某點的入邊條數 與之相對的是出度 出度 有向圖中某點作為圖中邊的起點的次數之和 某點的出邊條數 拿上面那張圖來說,a和b兩點的出度均為1,入度為0,而c點的入度為2 在前面已經說過,我們將每一項工...

演算法學習 拓撲排序(佇列應用)

題目 分析 乙個節點沒有節點指向 即入度為0 的時候可以順利輸出,如果有則不能。可以用鄰接矩陣的方式來儲存現有的圖,將某節點列下所有的相加後如果等於0這說明當前結點可輸出。這裡給出關鍵 和注釋 int graph 12 12 結點數為n,用鄰接矩陣graph n n 儲存邊權 int indegre...