X 拓撲排序 一

2021-08-21 19:39:03 字數 2796 閱讀 7284

描述

由於今天上課的老師講的特別無聊,小hi和小ho偷偷地聊了起來。

小ho:小hi,你這學期有選什麼課麼?

小hi:挺多的,比如***1,***2還有***3。本來想選yyy2的,但是好像沒有先選過yyy1,不能選yyy2。

小ho:先修課**是個麻煩的東西呢。

小hi:沒錯呢。好多課程都有先修課程,每次選課之前都得先查查有沒有先修。教務公布的先修課程記錄都是好多年前的,不但有重複的資訊,好像很多都不正確了。

小hi:這不正是輪到小ho你出馬的時候了麼!

小ho:哎??

我們都知道大學的課程是可以自己選擇的,每乙個學期可以自由選擇打算學習的課程。唯一限制我們選課是一些課程之間的順序關係:有的難度很大的課程可能會有一些前置課程的要求。比如課程a是課程b的前置課程,則要求先學習完a課程,才可以選擇b課程。大學的教務收集了所有課程的順序關係,但由於系統故障,可能有一些資訊出現了錯誤。現在小ho把資訊都告訴你,請你幫小ho判斷一下這些資訊是否有誤。錯誤的資訊主要是指出現了"課程a是課程b的前置課程,同時課程b也是課程a的前置課程"這樣的情況。當然"課程a是課程b的前置課程,課程b是課程c的前置課程,課程c是課程a的前置課程"這類也是錯誤的。

小ho拿出紙筆邊畫邊說道:如果把每一門課程看作乙個點,那麼順序關係也就是一條有向邊了。錯誤的情況也就是出現了環。我知道了!這次我們要做的是判定乙個有向圖是否有環。

小hi:小ho你有什麼想法麼?

《小ho思考了一會兒》

小ho:乙個直觀的演算法就是每次刪除乙個入度為0的點,直到沒有入度為0的點為止。如果這時還有點沒被刪除,這些沒被刪除的點至少組成乙個環;反之如果所有點都被刪除了,則有向圖中一定沒有環。

小hi:good job!那趕快去寫**吧!

小ho又思考了一會兒,撓了撓頭說:每次刪除乙個點之後都要找出當前入度為0的點,這一步我沒想到高效的方法。通過掃瞄一遍剩餘的邊可以找所有出當前入度為0的點,但是每次刪除乙個節點之後都掃瞄一遍的話複雜度很高。

小ho:我明白了,這個問題可以這樣來解決:

1. 計算每乙個點的入度值deg[i],這一步需要掃瞄所有點和邊,複雜度o(n+m)。

2. 把入度為0的點加入佇列q中,當然有可能存在多個入度為0的點,同時它們之間也不會存在連線關係,所以按照任意順序加入q都是可以的。

3. 從q中取出乙個點p。對於每乙個未刪除且與p相連的點q,deg[q] = deg[q] - 1;如果deg[q]==0,把q加入q。

4. 不斷重複第3步,直到q為空。

最後剩下的未被刪除的點,也就是組成環的點了。

小hi:沒錯。這一過程就叫做拓撲排序

小ho:我懂了。我這就去實現它!

< 十分鐘之後 >

小ho:小hi,不好了,我的程式寫好之後編譯就出詭異錯誤了!

小hi:詭異錯誤?讓我看看。

小hi湊近電腦螢幕看了看小ho的源**,只見小ho寫了如下的**:

int edge[ maxn ][ maxn ];
小hi:小ho,你有理解這題的資料範圍麼?

小ho:n最大等於10萬啊,怎麼了?

小ho:啊?!那我應該怎麼?qaq

小hi:這裡就教你乙個小技巧好了:

這道題目中n的資料範圍在10萬,若採用鄰接矩陣的方式來儲存資料顯然是會記憶體溢位。而且每次列舉乙個點時也可能會因為列舉過多無用的而導致超時。因此在這道題目中我們需要採用鄰接表的方式來儲存我們的資料:

常見的鄰接表大多是使用的指標來進行元素的串聯,其實我們可以通過陣列來模擬這一過程。

int head[ maxn + 1] = ;	// 表示頭指標,初始化為0

int p[ maxm + 1]; // 表示指向的節點

int next[ maxm + 1] = ; // 模擬指標,初始化為0

int edgecnt; // 記錄邊的數量

void addedge(int u, int v)

// 列舉邊的過程,u為起始點

for (int i = head[u]; i; i = next[i])

小ho:原來還有這種辦法啊?好咧。我這就去改進我的演算法=v=

輸入

第1行:1個整數t,表示資料的組數t(1 <= t <= 5)

接下來t組資料按照以下格式:

第1行:2個整數,n,m。n表示課程總數量,課程編號為1..n。m表示順序關係的數量。1 <= n <= 100,000. 1 <= m <= 500,000

第2..m+1行:每行2個整數,a,b。表示課程a是課程b的前置課程。

輸出

第1..t行:每行1個字串,若該組資訊無誤,輸出"correct",若該組資訊有誤,輸出"wrong"。

sample input

2

2 21 2

2 13 2

1 21 3

sample output

wrong

correct

#includeusing namespace std;

const int maxn=100005;

vectorvec[maxn];

queueque;

int m,n,a,b,t,indeg[maxn];

bool topsort()

if(topsort())

cout<

else

cout<

}return 0;

}

0x20 拓撲排序,bitset

拓撲排序,鏈式前向星,bitset 給定一張n個點m條邊的有向無環圖,分別統計從每個點出發能夠到達的點的數量。const int n 30020 int n,m struct edgeedge n int head n cnt int in n seq n 拓撲排序後的序列 bitsetf n vo...

1174 拓撲排序 一

時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述由於今天上課的老師講的特別無聊,小hi和小ho偷偷地聊了起來。小ho 小hi,你這學期有選什麼課麼?小hi 挺多的,比如 1,2還有 3。本來想選yyy2的,但是好像沒有先選過yyy1,不能選yyy2。小ho 先修課 是個...

python 拓撲排序 Python 拓撲排序

python 拓撲排序 在圖論中,由乙個有向無環圖的頂點組成的序列,當且僅當滿足下列條件時,稱為該圖的乙個拓撲排序 英語 topological sorting 每個頂點出現且只出現一次 若a在序列中排在b的前面,則在圖中不存在從b到a的路徑。print 拓撲排序結果 g.topologicalso...