1. 程式人生 > >任意兩點之間的最短路徑問題(Floyd-Warshall演算法)

任意兩點之間的最短路徑問題(Floyd-Warshall演算法)

求解所有兩點之間的最短路問題叫做任意兩點之間的最短路問題。Floyd-Warshall演算法考慮的是
 一條最短路徑上的中間結點。例如,簡單路徑p={v1,v2,...vl}上的中間結點指的是路徑p上除了v1和 vl之外的任意節點,也就是處於集合{v2,v3,...vl-1}中的節點。
Floyd-Warshall演算法基於以下: 
假定圖G的所有頂點為V={1,2,3,...,n},考慮其中的一個子集{1,2,..,k},這裡的K是小於n的整數。
對於任意的節點i,j屬於V,從i到j的所有中間結點都取自於集合{1,2,3,...,k}的路徑,並設p為其中權重最小的路徑,也就是說路徑p是簡單路徑。Floyd-Warshall演算法利用了路徑p和從i到j之間中間結點
取自集合{1,3,..,k-1}的最短路徑之間的關係。該關係依賴於結點k是否是路徑p上的一箇中間節點。
    (1)如果結點k不是路徑p上的中間結點,則路徑p上的所有中間結點都屬於集合{1,2,...,k-1}.所以,從結點i到結點j的中間結點取自於結合{1,2,...,k}的一條最短路徑。
    (2)如果結點k是路徑p上的中間結點,則路徑p可以分解為i~k,k~j。
通過以上分析,可以得出以下結論:
記i到j的最短路徑為d[i][j],那麼具有以下遞推公式:
d[i][j]= d[i][j]  最短路徑不通過k
       = min(d[i][j],d[i][k]+d[k][j]) 最短路徑通過k可以不斷的使用同一個公式進行更新 
       min(d[i][j],d[i][k]+d[k][j]) 
以上演算法使用DP策略,可以在O(|V|3)時間裡求得所有兩個結點之間的最短路徑。
int d[MAX_V][MAX_V]; //d[u][v]表示邊e=(u,v)的權值(不存在設為INF,d[i][i]=0)
int V; //頂點數目

void floyd_warshall(){
    for(int k=0;k<V;k++){
        for(int i=0;i<V;i++){
            for(int j=0;j<V:j++){
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            } 
        }
    }
}