(10)圖算法2: 最小生成樹, 最短路徑

最小生成樹(MST)問題

  • 對象: 該問題總是針對連通無向圖G = (V, E);
  • 總體算法
    • 這個算法理出大概的思路, 真正實現還分為點和邊兩種方式;
Generic-MST(G, w)  //w是權重函數
A = ?
while A does not form a spanning tree 
    find an edge(u,v) that is safe for A
    A = A∪(u,v)
return A  //the minimum spanning tree
  • 總體性質: A是圖G=(V, E)中E的在SpanningTree中的邊的集合, 如果(u,v)是橫跨切割(S, V-S)的輕量級邊, 其中S是SpanningTree的意思, 那么邊(u, v)對于集合A是安全的;

證明: (分類討論)
--如果(u, v)在STree中, 那么命題得證(安全邊才能被收入A中);
--如果(u,v)不在STree中, 因為u,v兩個點都在STree中, 那么必然在A中已經通過某種路徑相連, 這條路徑加上(u,v)邊會形成一個環路, 且此時至少有兩條邊跨越了切割, 一個是(u, v), 另外一個不妨寫作(x, y). 若斷掉(x,y)留下(u, v) 則此時T'.w = T.w + w(u, v) - w(x, y), 因為(u, v)是輕量級邊, 所以T'.w <= T.w, 所以說(u,v)邊是安全的;

prim算法

  • 思路: 并點, 不斷找新生成樹的切割面的最短邊, 是典型的貪心算法;
MST-Prim(G, w, r)  //Graph, weight, root
for each u ∈ G.V
    u.key = ∞
    u.parent = null
r.key = 0
Q = G.V  //initiate a priority queue, 初始化結束
while Q != ?:
    u = Extract-Min(Q)  //依據的是u.key是Q中最小的;
    for each v∈G.Adj[u]:  
        if v∈Q and w(u, v)<v.key:
            v.parent = u
            v.key = w(u, v)

Note: 獲取MST的時候, 只要讓每個非root的結點u輸出(u, u.parent)邊;

  • 時間復雜度分析:
    (1) 使用二維數組W存儲weight, 一維數組V存儲結點: 初始化操作Θ(V);Extra-Min操作V次, 每次耗時Θ(V), 所以這個環節是Θ(V^2); 對邊的操作, 總共有E條邊, 每次耗時都是Θ(1), 因此這個環節Θ(E); 總體耗時因此是Θ(V^2+E);
    (2) 使用二叉堆構建最小優先隊列, Extract-Min耗時總共O(VlgV), 對邊的操作需要做E次Decrease-Key, 耗時總共O(ElgV); 總體耗時因此為O((V+E)lgV), 因為E>=V-1總是成立, 因此可以寫作O(ElgV);
    (3) 使用斐波那契堆實現最小優先隊列Q的話, Extract-Min時間仍是lgV, 但是Decrease-Key下降到O(1), 因此總體上時間是O(VlgV+E), 小于O(ElgV).

Kruskal算法

  • 思路: 并邊, 不斷找整個圖中最短邊, 只要不構成環, 即相互不連通, 就并入, 也是貪心算法;.
MST-Kruskal(G, w)
A = ?
for each u ∈ G.V
    Make-Set(u)
sort the edges of G.E as ascending order by weight w  //到此初始化完成
for edge(u, v) of the sorted edge sequence
    if Find-Set(u) != Find-Set(v):
        A = A ∪ { (u,v) }  //add edge to A;
        Union(u, v)  //combine two trees
return A  //A is the tree;
  • 時間復雜度分析: 排序消耗了O(ElgE), 在改進過的并查集中, Find-Set總共做了E次, 消耗O(E), 而Union總共做了V次, 消耗O(Vα(V)), 其中α(V)<=4, 可以看作O(lgV), 因此Union消耗了O(VlgV), 因此并邊循環總共消耗O(E+VlgV), 顯然dominator是排序操作, 因此總體來說 T = O(ElgE).

網路最短路徑問題

  • 對象: 帶權重的有向圖G = (V, E); 注意和最小生成樹的主要區別在于這是有向圖!!!

共用方法

  • 初始化
Initialize-Single-Source(G, s)
for each vertex v ∈ G.V:
    v.d = ∞
    v.parent = null
s.d = 0
  • 松弛操作
Relax(u, v, w)
if v.d > u.d+w(u,v):
    v.d = u.d+w(u,v)
    v.parent = u

松弛定理: 對v點, 如果從s點到vi確實存在一條最短路徑, 那么只要(s, v1), (v1, v2), ... (vi-1, vi)都被依次執行了relax操作, 那么vi.d = δ(s, vi). 該性質的成立與其他穿插在該序列中間的松弛操作無關.

  • 也就是說, 接下去的三個算法, 我們都要檢查松弛定理是否能運用, 只要能運用, 算法是正確的;

1. 一般情況下的單源最短路徑問題

  • 條件寬松: 允許出現負權重的環路;
Bellman-Ford(G, w, s) {
Initialize-Single-Source(G, s)
for i = 1~|V|-1:
    for each edge(u, v) ∈ G.E:  
        relax(u, v)
for each edge(u, v) ∈ G.E:
    if v.d >u.d+w(u, v):  //只要任何一條邊仍能繼續松弛, 那么說明有負權重的環路存在;
        return FALSE
return TRUE
}

正確性:
(1) 對某個點vi來說, 從s如果有一條最短路徑, 那么在算法的第一個for循環, 到第i次循環, 該最短路徑上的邊(s, v1), (v1, v2)...(vi-1,vi)都將被松弛, 因此該算法能滿足松弛定理, 使得vi.d = δ(s, vi);
(2) 最短路徑上界定理: 對所有的最短路徑來說, 最多只能有V-1條邊, 否則將形成一個環. 因此Bellman-Ford算法只需要V-1輪全體relax就能cover到即使是最長的那條最短路徑.

  • 時間復雜度分析: 主要時間消耗在V-1次輪的全體relax, 一共消耗了O(VE);

2. 有向無環圖中的單源最短路徑問題

  • 條件收緊: 允許使用負權重的邊;
  • 借助拓撲序
DAG-Shortest-Path(G, w, s) {
topologically sort the vertices of G
Initialize-Single-Source(G, s)
for each vertex u taken by the sorted order:
    for each v of G.adj[u]:
        Relax(u, v, w)
}

正確性: 因為是按照拓撲序對所有的邊進行松弛, 因此最短路徑上的邊(s, v1), (v1, v2)...(vi-1,vi)的邊, 都會被依次松弛, 盡管中間可能穿插其他的松弛, 最后必然能實現vi.d = δ(s, vi)

迪杰斯特拉算法

  • 條件進一步收緊: 只允許非負權重的邊;
  • 思路:
    對每個節點賦值∞, 每次都并一個距離最小的結點, 同時更新該結點的adj結點, 不斷迭代;
Dijkstra(G, w, s) {
Initialize-Single-Source(G, s)
S = ?
Q = G.V  //初始化完成
while Q != ?:
    u = Extract-Min(Q)
    S = S∪{u}  //add u to S;
    for each vertex v of G.adj[u]:
        Relax(u, v, w)
}

正確性: Dij算法每次收入的點是當前Q中(尚未被染色的)滿足d最小的點u, u.d此時已經滿足被所有S中能到v的點給更新了. 那么為什么不擔心之后加入S的點可能還會再減小v.d呢? 這是因為之后再加S的點, 必須經過之前的S的點, 這些后加點的v.d只可能在已有能連到它的點的基礎上遞增, 因為Dij算法要求圖中沒有負權重邊.

  • 時間復雜度分析:
    (1) 使用二維數組W存儲weight, 一維數組V存儲結點: 初始化操作Θ(V);Extra-Min操作V次, 每次耗時Θ(V), 所以這個環節是Θ(V^2); 對邊的操作, 總共有E條邊, 每次耗時都是Θ(1), 因此這個環節Θ(E); 總體耗時因此是Θ(V^2+E); (注意到V-1<=E<=V^2, 因此可以寫成Θ(V^2)).
    (2) 使用二叉堆構建最小優先隊列, Extract-Min耗時總共O(VlgV), 對邊的操作需要做E次Decrease-Key, 耗時總共O(ElgV); 總體耗時因此為O((V+E)lgV), 因為E>=V-1總是成立, 因此可以寫作O(ElgV);
    (3) 使用斐波那契堆實現最小優先隊列Q的話, Extract-Min時間仍是lgV, 但是Decrease-Key下降到O(1), 因此總體上時間是O(VlgV+E), 小于O(ElgV).
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容