計算拓撲序列的乙個方式是,用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
位置的元素取值,所以最後輸出拓撲序列的時候可以直接從0
到n-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...