本章將複習一下圖論的基本理論。如果讀者以前接觸過圖算法,那麼可以便可以馬上開始本章的學習;如果讀者以前沒有相關圖算法背景知識,我們建議最好還是對其有一個瞭解,可以去看Cormen, Leiserson, 和Rivest寫的Introduction to Algorithms(《算法導論》)。
|
V = {v, b, x, z, a, y } E = { (b,y), (b,y), (y,v), (z,a), (x,x), (b,x), (x,v), (a,z) } G = (V, E) |
圖一 是該圖的圖示版。邊(x,x)叫做閉包。邊(b,y)和另一條(b,y)邊是平行邊,平行變僅僅出現在多重圖中(一般有向圖和無向圖是不允許出現的)。
下面我們將演示一個與圖一相似的圖,不過這次是無向的。圖二是該圖的圖示。閉包是不允許出現在無向圖中的。該圖是邊(b,y)的無向版本,相同的頂點和去除方向的邊。相同的邊被刪除,有些邊被合併,比如(a,z)和(z,a)。無向圖的有向版本是把其中每條邊換成兩條,每一條指向一個方向。
|
V = {v, b, x, z, a, y } E = { (b,y), (y,v), (z,a), (b,x), (x,v) } G = (V, E) |
現在開始講講圖的專業術語吧。如果邊(u,v)屬於一個圖,那麼頂點v是頂點u的鄰接點。在一個有向圖中,邊(u,v)是頂點u的出邊、頂點v的入邊。在一個無向圖中,邊(u,v)是與u,v關聯的。
在圖一中,頂點y是頂點b的鄰接點(但是b不是y的鄰接)。邊(b,y)是b的出邊,是y的入邊。在 圖二中,y是b的臨界點,反之亦然。邊(y,b)是與y和b關聯的。
圖的鄰接矩陣表示的就是一個V×V的2維數組。數組中的每一個元素auv存儲一個布爾值,該值表示邊(u,v)是否出現在圖中。圖三表示的是圖一的鄰接矩陣(刪除了平行邊(b,y))。存儲一個鄰接矩陣需要的空間是O(V2)。訪問、增加、刪除一條邊的複雜度是O(1)。增加或者刪除一個頂點需要重新分配空間並且拷貝整張圖到新的空間,負責度是O(V2)。 adjacency_matrix 類實現了按照BGL的圖接口規範實現了鄰接矩陣數據結構。
圖的鄰接列表表示的是每個頂點的出邊序列。對於一個稀疏圖來講,該表示法節省了空間,因為僅需了O(V +
E)大小的內存。而且,訪問頂點出邊更加有效率。邊得插入操作複雜度是O(1),但是訪問制定邊的效率是O(α),α表示矩陣的
稀疏因子(稀疏因子等於最大的頂點出度)。圖四表示的是圖一的鄰接列表。
adjacency_list 類是鄰接列表表示法的一個實現。
圖的邊列表表示就是一個邊的序列,其中每條邊使用一個頂點ID對來表示的。該表示法僅需要O(E)大小的內存。邊插入複雜度是O(1),但是訪問一個指定邊的複雜度是O(E)(效率低下)。圖五表示了 圖一的邊列表表示。
edge_list適配器類內被用來實現邊列表表示。
樹邊是通過圖搜索算法遍歷一個圖時所建立的搜索樹的邊。如果遍歷邊(調用 visitor 的explore
()方法)(u,v)時,點v首先被遍歷到,那麼邊(u,v)就是一條樹邊。在搜索樹中,後向邊連接頂點到他們的祖先。所以邊(u,v)中,點v一定是點
u的祖先。閉包被認為是反向邊。前向邊是非樹邊,搜索樹中(u,v)連接點u到它的子孫節點v。交叉邊是不屬於前面三種定義的邊。
廣度優先搜索(BFS)是指從某點開始遍歷整張圖,遍歷順序是首先遍歷該點的鄰居結點會,然後是它鄰居節點的鄰居節點優先遍歷到,直至遍歷完整張 圖。可以把深度優先遍歷想像成石子落入水中時激起的漣漪,在相同波浪的頂點和源點的距離是相同的。發現點是該算法瀏覽時首先遇到的點,結束點是遍歷完它所 有鄰居的最後一個點。下面有一個例子將幫助你理解。圖六中展示了一幅圖,並且在圖下面列出了BFS(深度優先算法)的算法中頂點的發現和結束順序。
order of discovery: s r w v t x u y我們從s點開始,首先訪問的是r和w(s的兩個鄰居)。它的兩個鄰居都被訪問過後,我們將訪問r的鄰居(頂點v),然後訪問w的鄰居(r和w的發現順序無所謂)t和x。最後,我們訪問t和x的鄰居u和y。
order of finish: s r w v t x u y
為了能夠知道我們在圖中的位置以及知道將要訪問的下一個點,BFS算法需要對頂點進行染色(color)(請參考 Property Maps一節來瞭解更多關於圖屬性的細節)。顏色值既可以放在圖結構內,也可以作為算法的參數傳進去。
DFS一個比較有意思的特性是按點的發現和結束順序插入到括號中,方法是:把發現一點放到左括號,把結束一點放到右括號,最後形成了一個嵌套的括號集合。圖七展示了DFS對於一個無向圖的應用,該圖邊上已經標好了遍歷的順序。下面我們列出了發現和結束的順序,以及嵌套的括號集合。DFS是其他一些算法的核心,比如托普排序和連通份量算法。DFS算法還能檢測是圖中是否存在環(參考文件依賴例子中的Cylic Dependencies(循環依賴)一節)。
order of discovery: a b e d c f g h i
order of finish: d f c e b a
parenthesis: (a (b (e (d d) (c (f f) c) e) b) a) (g (h (i i) h) g)
一個網絡流是一個以頂點s為源點,以頂點t為接受點的有向圖G=(V,E)。每條邊e均具有一個非負容量(capacity )c(e)而且每個頂點對還有一個流f(e)。流一定要滿足下面三個條件:
|f| = sumu in V f(u,t) = sumv in V f(s,v)
一條邊的剩餘容量為:r(u,v) = c(u,v) - f(u,v)。如果r(u,v)>0則該邊是有餘量的,包含該邊的圖為有餘量圖。如果r(u,v)=0,則該邊為飽和的。
最大流問題是指確定|f|的最大值和圖中每個頂點對相應的流是多少。
解決最大流問題算法已經有很長歷史了,首先提出解決該問題的算法是 Ford 和 Fulkerson.對於數據最通用的算法是Goldberg提出的push-relabel算法,該算法基於Karzanov提出的前向(preflow)概念。
| Copyright c 2000-2001 | Jeremy Siek, Indiana University (jsiek@osl.iu.edu) |