1. 程式人生 > >【圖論】有向無環圖的拓撲排序

【圖論】有向無環圖的拓撲排序

1. 引言

有向無環圖(Directed Acyclic Graph, DAG)是有向圖的一種,字面意思的理解就是圖中沒有環。常常被用來表示事件之間的驅動依賴關係,管理任務之間的排程。拓撲排序是對DAG的頂點進行排序,使得對每一條有向邊(u, v),均有u(在排序記錄中)比v先出現。亦可理解為對某點v而言,只有當v的所有源點均出現了,v才能出現。

下圖給出有向無環圖的拓撲排序:

下圖給出的頂點排序不是拓撲排序,因為頂點D的鄰接點E比其先出現:

2. 演算法原理與實現

拓撲排序的實現演算法有兩種:入度表、DFS,其時間複雜度均為\(O(V+E)\)

入度表

對於DAG的拓撲排序,顯而易見的辦法:

  • 找出圖中0入度的頂點;
  • 依次在圖中刪除這些頂點,刪除後再找出0入度的頂點;
  • 然後再刪除……再找出……
  • 直至刪除所有頂點,即完成拓撲排序

為了儲存0入度的頂點,我們採用資料結構(亦可用佇列);演算法的視覺化可參看這裡

圖用鄰接表(adjacency list)表示,用陣列inDegreeArray[]記錄結點的入度變化情況。C實現:

// get in-degree array
int *getInDegree(Graph *g) {
    int *inDegreeArray = (int *) malloc(g->V * sizeof(int));
    memset(inDegreeArray, 0, g->V * sizeof(int));
    int i;
    AdjListNode *pCrawl;
    for(i = 0; i < g->V; i++) {
        pCrawl = g->array[i].head;
        while(pCrawl) {
            inDegreeArray[pCrawl->dest]++;
            pCrawl = pCrawl->next;
        }
    }
    return inDegreeArray;
}

// topological sort function
void topologicalSort(Graph *g) {
    int *inDegreeArray = getInDegree(g);
    Stack *zeroInDegree = initStack();
    int i;
    for(i = 0; i < g->V; i++) {
        if(inDegreeArray[i] == 0)
            push(i, zeroInDegree);
    }

    printf("topological sorted order\n");
    AdjListNode *pCrawl;
    while(!isEmpty(zeroInDegree)) {
        i = pop(zeroInDegree);
        printf("vertex %d\n", i);

        pCrawl = g->array[i].head;
        while(pCrawl) {
            inDegreeArray[pCrawl->dest]--;
            if(inDegreeArray[pCrawl->dest] == 0)
                push(pCrawl->dest, zeroInDegree);
            pCrawl = pCrawl->next;
        }
    }
}

時間複雜度:得到inDegreeArray[]陣列的複雜度為\(O(V+E)\);頂點進棧出棧,其複雜度為\(O(V)\);刪除頂點後將鄰接點的入度減1,其複雜度為\(O(E)\);整個演算法的複雜度為\(O(V+E)\)

DFS

在DFS中,依次列印所遍歷到的頂點;而在拓撲排序時,頂點必須比其鄰接點先出現。在下圖中,頂點5比頂點0先出現,頂點4比頂點1先出現。

在DFS實現拓撲排序時,用來儲存拓撲排序的頂點序列;並且保證在某頂點入棧前,其所有鄰接點已入棧。DFS版拓撲排序的視覺化參看這裡

C實現:

/* recursive DFS function to traverse the graph,
* the graph is represented by adjacency list
*/
void dfs(int u, Graph *g, int *visit, Stack *s) {
   visit[u] = 1;
   AdjListNode *pCrawl = g->array[u].head;
   while(pCrawl) {
       if(!visit[pCrawl->dest])
           dfs(pCrawl->dest, g, visit, s);
       pCrawl = pCrawl->next;
   }
   push(u, s);
}

// the topological sort function
void topologicalSort(Graph *g) {
   int *visit = (int *) malloc(g->V * sizeof(int));
   memset(visit, 0, g->V * sizeof(int));
   Stack *s = initStack();
   int i;
   for(i = 0; i < g->V; i++) {
       if(!visit[i]) dfs(i, g, visit, s);
   }

   // the order of stack element is the sorted order
   while(!isEmpty(s)) {
       printf("vertex %d\n", pop(s));
   }
}

時間複雜度:應與DFS相同,為\(O(V+E)\)

3. 參考資料

相關推薦

排序

1. 引言 有向無環圖(Directed Acyclic Graph, DAG)是有向圖的一種,字面意思的理解就是圖中沒有環。常常被用來表示事件之間的驅動依賴關係,管理任務之間的排程。拓撲排序是對DAG的頂點進行排序,使得對每一條有向邊(u, v),均有u(在排序記錄中)比v先出現。亦可理解為對某點v而言,只

bzoj1143: [CTSC2008]祭祀river的最長反鏈

1143: [CTSC2008]祭祀river Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3192  Solved: 1632 [Submit][Status][Discuss] Description   在遙遠

HDU 3249 Test for job (上的最長路,DP)

code head struct sin == cout article scanf for ?? 解題思路: 求有向無環圖上的最長路。簡單的動態規劃#include <iostream> #include <cstring> #include

HOJ 13845 Atomic Computer的動態規劃

-1 會有 bsp pre 但是 自帶 += 排列組合 開始 考慮任意一個數字,任何一個都會有奇怪的。。性質,就是一個可以保證不重復的方案——直接簡單粗暴的最高位加數字。。於是,如同上面的那個題:+1、-1、0 但是考慮到65536KB的標準內存限制,會得出一個奇怪的性質,

CSU 1804 - - [樹形DP]

其中 如果 init max 枚舉 time 包含 mod %d 題目鏈接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 Bobo 有一個 n 個點,m 條邊的有向無環圖(即對於任意點 v,不存在從點 v 開

c/c++ directed acycline graph

rect 如果 拓撲排序 type 第一個 ima 結構 alt lse c/c++ 有向無環圖 directed acycline graph 概念: 圖中點與點之間的線是有方向的,圖中不存在環。用鄰接表的方式,實現的圖。 名詞: 頂點的入度:到這個頂點的線的數量。 頂

狄克斯拉特算法。 適用於,加權,且負權邊,的最短路徑計算。

app 計算 aaaaaa ict nbsp aps ces find aaaaa 沒事時看的一道題,解完後發現這居然是一個算法。 就在這裏拷貝一份,免得後面自己都忘了自己原來寫的是什麽東西。 核心思路: 1、找到臨近節點中路徑最短的那一個。 2、更新從該節點去它臨近節點的

路==路徑規劃

一道面試題  我們有⼀一個有向⽆無環圖,權重在節點上。 需求:從⼀一個起點開始,找到⼀一條節點權重之和最⼤大的最優路路徑。 輸⼊入: n個節點,m個路路徑,起點 輸出: 最優路路徑的權重值之和 舉例例: 3個節點與權重: A=1, B=2, C=2 3條路路徑: A->

DAG 排序 程式碼解釋

目錄: DAG定義 舉例描述 實際運用 演算法描述 演算法實戰 演算法視覺化 定義 在圖論中,由一個有向無環圖的頂點組成的序列,當且僅當滿足下列條件時,稱為該圖的一個拓撲排序(英語:Topological sorting)。 每個頂點出現且只出現一

Park[的DP]

---- From decoration       #include<bits/stdc++.h> #define N 2005 #define M 5005*2 #define LL long long using namespace std;

構建(DAG)模型解決矩形巢狀問題 以(nyoj16為例)

 DAG(Directed Acyclic Graph):在圖論中,如果一個有向圖無法從某個頂點出發經過若干條邊回到該點,則這個圖是一個有向無環圖(DAG圖)。有向無環圖上的動態規劃是學習動態規劃的基礎。很多問題都可以轉化為DAG上的最長路和最短路或計數問題。 分析

(DAG)技術:超越區塊鏈的分散式賬本

一、起源 DAG(Directed Acyclic Graph,有向無環圖)是一種資料結構,最早提出在區塊鏈中加入DAG概念作為演算法,是在2013年的bitcointalk論壇,被稱作為“Ghost協議”,這一提議也是為了解決當時比特幣的擴容問題。後來,在NXT社群,

NOIP模擬 (玄學建+最短路)

內網傳送門 【題目分析】 SPFA竟然有人亂搞A了?orz(蒟蒻亂搞只有40pts qwq) 很巧妙的建圖思路,將每條路徑視為一個點,從一條路徑i到達另一條路徑j,如果w[i]<w[j],那麼會產生w[j]-w[i]的費用,否則不會產生任何費用。 所以考慮將所有

文章目錄 在和有向圖相關的實際應用中,有向環特別的重要。 優先順序限制下的排程問題:給定一組需要完成的任務,以及一組關於任務完成先後次序的優先順序限制。在滿足限制條件的前提下應該如何安排並完成所有任務? 對於任意一個這樣的問題,我們都可以畫出一張有向圖,其中頂點

在DAG()上的常見推論

1.DAG上某條邊可能被經過的次數數量: 通過在DAG上的總結,再結合我們在小學學過的乘法原理,我們可以考慮到一個規律:在一條邊M(u->v)上,通過M的方法數量為從源點到達u的方式數量*從終點

SparkDAG圖解與演示

目錄:1、有向無環圖 2、程式碼結構 3、程式碼學習步鄹及方法 4、重點程式碼講解 5、程式碼展現 6、執行結果 ——————————————————————————————————— 1、有向無環圖 在圖論中,如果一個有向圖無法從某個頂點出發經過若干條邊回到該點,則這個

資料結構——(AOV網、AOE網)

有向無環圖是一個無環的有向圖, 是描述一項工程或系統的進行過程的有效工具。幾乎所有的工程都可分為若干個稱做活動的子工程。 有兩種常用的活動網路        1. AOV網(Activity On Vertices)——用頂點表示活動的網路  

->->排序

文字描述   關於有向無環圖的基礎定義:     一個無環的有向圖稱為有向無環圖,簡稱DAG圖(directed acycline graph)。DAG圖是一類較有向樹更一般的特殊有向圖。        舉個例子說明有向無環圖的應用。假如有一個表示式: ((a+b)*(b*(c+d))+(c+d)*e

中求最長路徑

// A C++ program to find single source longest distances in a DAG #include <iostream> #include <list> #include <stack> #include <limit

深度優先演算法(DFS)遍歷計算最優路徑

遍歷有向無環圖,尋找最優路徑: 1、假設我們從A點走到B點,可以經過不同的地方,分別用1,2,3,4,5,6表示,A用0表示,B用7表示,從一個地方到另一個地方,中間的路好走的程度用w表示,w越大表示越好走,因此我們可以建立數學模型如下圖1所示: 圖1 2、根據數學模