• 沒有找到結果。

Shortest Path in class

N/A
N/A
Protected

Academic year: 2022

Share "Shortest Path in class"

Copied!
27
0
0

加載中.... (立即查看全文)

全文

(1)

Shortest Path in class

Lecture by zolution Credit by TreapKing

2018/06/16

(2)

Brainstorming Brainstorming

• 給定一個有權重的無向圖

你要如何把它轉成另一個無向圖,讓他可以使用 BFS 解決最短路 呢?

(3)

Floyd-Warshall Floyd-Warshall

• 感覺對對的,但總有種不踏實感

• 為什麼說這個算法是某種 DP 呢?

(4)

我大 DP 我大 DP

• 原本的狀態:

• d[i][j]: 從點 i 走到點 j 的最短距離

• for k = 1..n

• for i = 1..n

• for j = 1..n

• d[i][j] = min(d[i][j], d[i][k]+d[k][j]);

(5)

我大 DP 我大 DP

• 改個狀態:

• d[k][i][j]: 從點 i 走到點 j 的最短距離,且除了 i 跟 j 以外,只能經過前 k 個點

• for k = 1..n

• for i = 1..n

• for j = 1..n

• d[k+1][i][j] = min(d[k][i][j], d[k][i][k+1]

+d[k][k+1][j]);

(6)

Dijkstra Dijkstra

為什麼他是對的?

(7)

Dijkstra Dijkstra

先說,不能有負邊

(8)

Dijkstra Dijkstra

那為什麼不能有負邊

(9)

Dijkstra Dijkstra

O(E+V 2 )

還可以更快嗎?

(10)

Dijkstra Dijkstra

(11)

Dijkstra Dijkstra

(12)

Dijkstra Dijkstra

• 從一個集合裡面找出最小的數字

• priority_queue(heap)!!

• 用 priority_queue 找到 d[] 最小的點,然後用它來更新其他點 的 d[]

• 原本的做法: (V 輪 ) * ((O(V) 找到 d[] 最小的點 ) + ( 更新 連到它的點 )) = O(E+V2)

• 新做法: (V 輪 ) * ((O(logV) 找到 d[] 最小的點 ) + ( 更新連 到他的點 ) ,把更新後的點放進 heap) = O((V+E)logV)

(13)

Dijkstra Dijkstra

怎麼找出最短路徑本身?

(14)

最短路徑樹 最短路徑樹

• 每一個最短路徑一定都是簡單路徑

• 如果起點到每個點的最短路徑都唯一的話,那把這些路徑疊起來 會變成一棵樹

• 我們稱這種樹叫做最短路徑樹

• 如果最短路徑們不唯一的話,一樣會存在一顆最短路徑樹,只是 那棵樹不唯一

(15)

最短路徑樹 最短路徑樹

• 每一個最短路徑一定都是簡單路徑

• 如果起點到每個點的最短路徑都唯一的話,那把這些路徑疊起來 會變成一棵樹

• 我們稱這種樹叫做最短路徑樹

• 如果最短路徑們不唯一的話,一樣會存在一顆最短路徑樹,只是 那棵樹不唯一

• 樹上的節點,父節點是唯一的

• 紀錄 predecessor!

(16)

Bellman-Ford Bellman-Ford

(17)

Bellman-Ford Bellman-Ford

• 設 d[i] 是從起點走到點 i 的最短距離

• 根據定義: d[j] <= d[i]+e(i, j) ,否則 d[j] 就不是最短距離

• 小性質:只要對於所有的 (i, j) 都滿足 d[j] <= d[i]+e(i, j)

,而且對每個 j 都存在 d[j] = d[i]+e(i, j) ,那麼 d[] 就是 最短距離陣列

• 想法:如果找到一組 (i, j) 滿足 d[j] > d[i]+e(i, j) ,就把 d [j] 更新成 d[i]+e(i, j)

• 要怎麼更新?

• 亂更新!!

(18)

Bellman-Ford Bellman-Ford

(19)

Bellman-Ford Bellman-Ford

• 每次都跑完整個盤面怎麼感覺笨笨的

• 如果圖很大的話,每次就花一堆時間在更新後面的 inf 們

• 可不可以每次只跑那些有被更新到的點?

• SPFA(Shortest Path Faster Algorithm)!!

(20)

SPFASPFA

• 1. 一開始把起點 push 到 queue 裡面

• 2. 從 queue 裡面 pop 出一個點 u

• 3. 用 u 去放鬆 ( 更新 ) 其他點

• 4. 把所有被更新到的點都 push 到 queue 裡面

• 5. 如果 queue 已經空了,那麼算法結束。否則回到 2.

(21)

SPFASPFA

• 這個算法感覺聰明多了!

• 我們來看看它的時間複雜度進步了多少吧!

• O(VE)

• 足夠慘的時候,還是會跑到 VE 的

• 不過有些人說這東西期望上大概是 O(kE) , k 大概是 2

• 實務上其實挺快的,競賽的話就看出題者有沒有特別卡 ( 其實不 太好卡 )

(22)

怎麼卡 SPFA 怎麼卡 SPFA

• SPFA 感覺快快的,該怎麼卡呢?

• 生一個 V=sqrt(E) 的完全圖

• for i = 1..(n-1)

• e[i][i+1] = 1

• for i = 1..(n-1)

• for j = 1..n \ {i+1}

• e[i][j] = 10*n-2*i

• 這樣可以讓 SPFA 跑成大概 E*sqrt(E)

• 不知道有沒有別的卡法,而且好像也不一定卡得掉

(23)

小總結小總結

• Bellman-Ford :亂更新一通

• SPFA :好好寫的 Bellman-Ford

• Dijkstra :如果沒有負邊的話,利用這個好性質來更好的更新其 他點

(24)

各種比較各種比較

算法 Floyd-Warshall Bellman-Ford SPFA Dijkstra

時間複雜度 O(V3) O(VE) O(VE) (期望 O(kE)) O(V2) or O(ElogV)

處理負邊 O O O X

處理負環 X O O X

特點 好寫 沒用 可以處理負環 最快

(25)

負環負環

• 什麼叫做處理負環呢?

• 不是說好有負環的話就沒有最短路嗎?

• 可以拿來看有沒有負環

• 例如更新的次數太多

• 但沒負環一定沒有解嗎?

(26)

負環負環

(27)

負環負環

• 前面提到的可以處理負環的演算法都可以處理上一頁的那種情況

• 那要怎麼分辨一個有負環的圖存不存在一個 s-t 最短路呢?

• 更新太多次  有負環

• 如果有負環的話,從終點回朔回去,看有沒有經過重複的點

• 如果走到了重複的點,那就表示有負環

• 順帶一提,如果只是要判斷有沒有負環的話, Floyd-Warshall 也可以判斷有沒有負環,而且只要看一下有沒有 d[i][i]<0 就好

參考文獻

相關文件

貪心 Greedy. Lecture

貪心 Greedy. Lecture

貪心 Greedy. Lecture

Segment/Interval Tree in class. by

• 數學上有一個很類似的定義叫做凸函數 (convex function). • 上下顛倒後就叫凹函數

•  三分搜在有水平線的情況下,如果可以確定水平線的地方一定是 答案的話,才可以用三分搜找極值。..

Lecture by baluteshih Credit by zolution... Minimum

錯排數