1. 程式人生 > >所有節點對之間的最短路問題(All Pair Shortest Path)--《演算法導論》

所有節點對之間的最短路問題(All Pair Shortest Path)--《演算法導論》

給定一個有向圖求出裡面所有節點對之間的最短路徑。
問題的詳細描述見Wikipedia:https://en.wikipedia.org/wiki/Shortest_path_problem
介紹兩個演算法O(V3)的Floyd演算法和O(V2lgV+VE)的Jhonson演算法。分別應對稠密圖和稀疏圖的情況。

Floyd

這是一個動態規劃演算法。設dkiji,j之間所有中間節點全部取自<1,2,...,i,...,k>的一條最短路的權重。則狀態轉移方程如下

dkij={wijmin{dk1ij,dk1ik+dk1ij}x=0x!=0

虛擬碼

for k=1

to |V|
fori=1 to V
forj=1 to V
d[i][j]=min{d[i][j],d[i][k]+d[k][j]}

c++程式碼

void floyd(int n)
{
    memcpy(d,w,sizeof(w));//初始化d(0)
    for(int k=1 ; k<=n ; ++k)
        for(int i= 1 ; i<=n ; ++i)
            for(int j=1 ; j<=n ; ++j)
                d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
}

Johnson(用於稀疏圖)

Johnson演算法的核心思想是直接對每個頂點做一次Dijkstra,這樣時間複雜度只有O(VElgV)(用斐波那契堆實現只需O(V2lgV))對於稀疏圖來說是會漸進優於Floyd演算法的,但是我們知道Dijkstra演算法只能用於權重為正數的情況。所以要對圖上的權重進行重新對映一次。

重塑權重值
p:<v0,...,vi,...,vk>為從v0vk的一條最短路,則重塑的權重w必須滿足兩個條件:

1、w(p)=δ(v0,vk)w(p)=δ(v0,vk)
2、w(p)不包含負環w(p)不包含負環

下面證明取權重對映w

(u,v)=w(u,v)+h(u)h(v)時滿足條件。

w(p)=ni=1w(vi,vi1)

=ni=1w(vi,vi1)+h(v0)h(vk)

=w(p)+h(v0)h(vk)

第一條肯定滿足了,因為h(v0),h(vk)是預處理出來的常數,第二條,當p為一負權重的環路時,v0=v