算法導論(MIT 6.006 第15講 第16講 第17講)算法
最短路徑即擁有最小權重的路徑p;
路徑定義: p=<$v_0$,$v_0$,...,$v_k$>, 其中當$0\leq i<k$時,有 ($v_i$,$v_{i+1}$) $\in$ E;
路徑的權重:w(p)=$\Sigma{^{k-1}_{i=0}}w(v_i,v_{i+1})$ ;網絡
E與V的關係 E=O($V^2$ )。對於有向圖來說,假設有兩個頂點,v1,v2,他們之間只有4種鏈接狀況,依次類推
好比社交網絡上的喜歡能夠看作是正的權重,比喜歡能夠看作是負的權重函數
若是存在一個帶有負權重的邊,那麼每通過一個循環,會減小原有的權重值,這樣形成的現象是能夠獲得任何能夠獲得的權重值。好比路徑p=<S,A>權重是4,可是路徑p=<S,A,C,B,A>權重是3spa
d(v) 表示從源點s到當前節點v的路徑權重 ,$\pi[v]$表示當前最好的路徑上,v的前一個節點 ,經過這種方式就能重構整個最短路徑
針對沒有負權重的環code
Relax(u,v,w): select edge(u,v): if d[v]>d[u]+w(u,v): d[v]=d[u]+w(u,v) PI[v]=u until all edges have d[v] <= d[u]+w(u,v)
經過概括法,假設有 d[u] $\geq$ $\delta$(s,u)。已知的是$\delta(s,v)$表示s到v的最短路徑,那麼任意一個到v的頂點u和源點s到u的最短路徑一定大於等於$\delta(s,v)$,也就是
$$\delta(s,v)\leq\delta(s,u)+w(u,v)$$
經過前面的假設,則一定有 $\delta(s,v)\leq d[u]+w(u,v)=d[v]$ 。這說明,中間的過程的任意一個階段產生的結果d[v]都不會比$\delta$(s,v)還要小排序
構造以下結構的圖隊列
邊的權值按照$2^{n/2}$方式分配,圖中給出的6個點的示例,若是所有顯示的邊($v_0$,$v_2$)的權值爲$2^{n/2}$,並依次遞減到1
假設源點爲$v_0$,初始化選擇的路徑以下,能夠獲得從源點到各個點的路徑長度。圖片
此時,Relax($v_4$,$v_6$)的邊,會更新$v_0$到$v_6$的路徑長度爲13ci
再Relax($v_2$,$v_4$)的邊,會更新$v_0$到$v_4$的路徑長度爲10get
因爲新$v_0$到$v_4$的路徑長度變短,那麼($v_0$,$v_5$)的路徑會變短爲11
這個時候有可能先選的執行Relax的邊是 ($v_5$,$v_6$),那麼($v_0$,$v_6$)的路徑會變短爲12
再次Relax邊($v_4$,$v_6$),那麼($v_0$,$v_6$)的路徑會變短爲11
針對有n個頂點的狀況:
可發現,當Relax的邊($v_{n-2}$,$v_{n}$)權重爲1的時候,使得頂點d($v_n$)減1;當Relax邊($v_{n-4}$,$v_{n-2}$)權重爲2的時候,使得頂點d($v_n$)減2,也就是從權重按照 1,2,4,...,$2^{(n/2)-1}$,$2^{(n/2)}$的方式執行的過程當中,d($v_n$)須要執行減小的總次數爲1+2+4+...+$2^{(n/2)}$=$2^{(n/2)}-1$,也就是說,會執行的次數爲指數級別
若是在源點到目標節點通過的路徑上,通過環會致使權重減小,這個算法不會結束
DAG表示只是沒有環,能夠存在負邊權重
假設排序好的拓撲圖以下,對於初始化時,每一個源點到每一個節點的距離都認爲是 $\infty$
第一步從源點往下走,找到它的全部的邊,對邊執行Relax操做
源點執行完畢,而後按照拓撲排列的順序,從左往右執行,因爲Relax只更改小於的狀況,所以只有最後兩個節點的路徑值被更新
繼續往右執行Relax
繼續往右執行Relax
至此執行完畢,能夠看到源點到全部節點的最短路徑,從左到右分別是 $\infty$,0,2,6,5,3
使用Dijkstra算法。僞代碼算法以下:
Dijkstra(G,w,s): //G是圖,w是權值,s是源點 Initialize(G,s) // 初始化,設置d[s]=0,其它都是無窮,以及PI S <- {} //已知最短路徑的點的集合 Q <- V[G] //須要被處理的頂點,能夠看作是一個最小優先級隊列,根據d()值進行排序 while Q is not empty: //只要還有沒處理的節點 u <- Extract-Min(Q) //從節點中找出一個最小的路徑權重的節點,並從Q中移除 S <- S U {u} //將找到的節點併到S中 for each vertex v belong to Adj Relax(u,v,w) //對邊的d()值進行更新
例子以下,選擇A爲源點
括號中的值表示路徑距離
全部的耗時操做包括:
實現優先級隊列方式不一樣,耗時不一樣
最直觀的使用Dijkstra的感覺是:如下圖爲例:![]()
假設綠色的點是源點,若是用這樣長度的繩子將各個節點鏈接起來,那麼拎起綠色的球,從上往下懸掛,那些蹦直的線相加就是源點到各個點的最短距離,好比綠色是源點,到其它點的最短距離分別是 7,12,18,22(顏色依次是紫色、藍色、黃色、紅色)
Dikstra不會去看已經處理好的節點,只會處理沒有看到的節點,若是已經處理的節點都是最小的值,再不存在負權重環的狀況下,是不會出現使得路徑變小的狀況。詳見:https://stackoverflow.com/que...
使用Bellman-Ford算法。
Bellman-Ford(G,w,s): Initialuze(G,s) for i=1 to |V|-1: for each edge(u,v) belong to E: Relax(u,v,w) for each edge (u,v) belong to E: if d[v]>d[u]+w(u,v) report negative cycle exist
Bellman-Ford最終提供的是,若是沒有負權重的環,那麼能返回最短路徑(d[v]=$\delta(s,v)$),不然只是檢測出存在負權重的環
兩個for循環,分別爲V,E,因此時間複雜度就是O(VE)
只須要證實,若是不存在負權重的環,那麼通過Bellman-Ford有d[v]=$\delta(s,v)$。
取一條擁有最少邊的最短路徑p=<$v_0$,$v_1$,...,$v_k$>,其中$v_0$爲s,$v_k$=v。 若是不存在負權重的環,那麼說明p是一條簡單路徑,這代表,k$\leq$|V|-1。
這裏也不多是一個正環,即每通過這個環,權重增長,若是是那麼它就不是最短路徑了
當進行第一次循環的時候,取到的邊($v_0$,$v_1$)進行了Relax,那麼有 delta(s,$v_1$)=d[$v_1$]
進行第二次循環,取到的邊($v_1$,$v_2$)進行了Relax,那麼有delta(s,$v_2$)=d[$v_2$]
那麼通過k輪循環以後,有delta(s,$v_k$)=d[$v_k$],也就是說通過了|V|-1輪循環以後,每一個從源點可達的頂點都計算了最短路徑
簡單路徑(simple path):指除了起點和終點以外,其它頂點不會重複。對於簡單路徑p=<$v_0$,$v_1$,...,$v_k$>來說,若是k>=|V|,那麼路徑上總的頂點數是|V|+1,但實際只有 |V|個頂點,那麼一定存在一條重複的邊,使得非起點終點重複了,也就是說他不是簡單路徑了
通過|V|-1輪循環以後,若是還有一條邊可以Relax,那麼當前從s到v的最短路徑並非簡單路徑,由於全部的節點都已經看過了,這時候確定存在了重複的節點,也就是說存在一個負權重的環
不能,由於Bellman-Ford對於存在負權重的環的時候只會拋出異常,並無計算路徑,這實際是一個N-P的問題,即花的時間在指數級別或者之上
相似的,若是要求不通過負權重的環的狀況下,計算最短路徑,也並非件容易的事情