1,Dijkstra 算法一次性求得起始頂點到全部其它頂點的最短路徑,若是想要求解任意兩個頂點之間的最短路徑,可將圖中頂點做爲起始頂點執行 n 次 Dijkstra 算法就能夠了;算法
2,可能解決方案:數組
1,算法執行結束後,i 到 j 最短路徑值存儲於 dist[i][j] 中。最短路徑前驅結點存儲於 path[N][N] 中;spa
2,這種方法比較土;3d
3,問題的提法:code
1,已知一個各邊權值均大於 0 的帶權有向圖,對每一對頂點 vi != vj,求出 vi 與 vj 之間的最短路徑值以及最短路徑上的頂點;blog
4,Floyd 算法核心:遞歸
1,定義一個 n 階方陣序列:隊列
其中:get
2,懷疑當前兩個頂點間路徑不是最短路徑,所以 Floyd 算法嘗試經過其餘頂點中轉、直到找到一箇中轉點的中轉路徑最短;it
5,n 階方陣中元素的意義:
1,都是由鄰接方陣中的權值推得的;
2,此算法是經過遞推的方式獲得兩個頂點間最短路徑的;
3,把全部的頂點的中轉路徑都推導完了,也就獲得最小路徑了;
4,後面方陣的推導,包含着前面方陣的信息,且每次推導都是最小,直到推導了所有頂點,獲得最終最短路徑;
6,Floyd 算法精髓:
7,Floyd 算法的實現:
1,初始化:
1,本質:使用鄰接矩陣初始化 A(-1);
2,A(0), ..., A(n-1) 矩陣推導:
1,本質:使用中轉頂點逐步推導最短路徑;
2,最外層是在說 A(k)矩陣的循環,循環推導完後,獲得最短路徑矩陣 A(n-1),即爲所求;
8,如何記錄最短路徑上的各個頂點?
1,定義輔助矩陣:
1,int path[N][N]; // 路徑矩陣
1,path[i][j] 表示 i 到 j 的路徑上所通過的第 1 個頂點;
2,初始化:path[i][j] = -1; or paht[i][j] = j;
1,有直接的鏈接則設置爲 j,表示通過的第一個頂點爲終值頂點 j;
2,沒有鏈接的兩個頂點設置爲 -1;
3,修改:
1 if( (dist[i][k] + dist[k][j]) < dist[i][j] ) 2 { 3 dist[i][j] = dist[i][k] + dist[k][j]; 4 path[i][j] = paht[i][k]; 5 }
1,if 條件爲真,由 k 這個頂點中轉能夠獲得一條更短路徑,則由 i 到 j 這條路徑上所通過的第一個頂點就是由 i 到 k 這條路徑上通過的第一個頂點,由於由 k 中轉了下;
2,路徑矩陣示例:
1,由一個點的路徑推至其它路徑:
2,輔助矩陣和路徑:
9,Floyd 最短路徑算法實現:
1 /* floyd 每對結點之間最短路徑算法,返回值爲最短路徑;核心爲經過中轉頂點尋找更短路徑 */ 2 SharedPointer< Array<int> > floyd(int x, int y, const E& LIMIT) // O(n*n*n) 3 { 4 LinkQueue<int> ret; 5 6 if( (0 <= x) && (x < vCount()) && (0 <= y) && (y < vCount()) ) //頂點編號要合理 7 { 8 DynamicArray< DynamicArray<E> > dist(vCount()); // 定義二維數組,N*N 9 10 DynamicArray< DynamicArray<int> > path(vCount()); // 最短路徑的輔助數組 11 12 /* 定義二維數組 */ 13 for(int k=0; k<vCount(); k++) 14 { 15 dist[k].resize(vCount()); 16 path[k].resize(vCount()); 17 } 18 19 /* 初始值設置 */ 20 for(int i=0; i<vCount(); i++) 21 { 22 for(int j=0; j<vCount(); j++) 23 { 24 path[i][j] = -1; // i 和 j 是沒有邊的 25 26 dist[i][j] = isAdjacent(i, j) ? (path[i][j]=j, getEdge(i, j)) : LIMIT; // 鄰接了就設置,利用了逗號表達式,逗號表達式第一個參數是設置頂點,第二個是設置權值 27 } 28 } 29 30 /* 推導最短路徑矩陣 */ 31 for(int k=0; k<vCount(); k++) 32 { 33 for(int i=0; i<vCount(); i++) 34 { 35 for(int j=0; j<vCount(); j++) 36 { 37 /* 推導規則,用中間頂點中轉數據,看是否有最短路徑值 */ 38 if( (dist[i][k] + dist[k][j]) < dist[i][j] ) 39 { 40 dist[i][j] = dist[i][k] + dist[k][j]; // 若是獲得最短路徑,認爲其多是最短路徑,要更新其值 41 42 path[i][j] = path[i][k]; // 經過 k 頂點能夠找到最小值,則這個頂點找到了 43 } 44 } 45 } 46 } 47 48 while( (x != -1) && (x != y) ) // 推導到終止頂點爲止 49 { 50 ret.add(x); // 最短路徑上的各個頂點加到返回值中 51 52 x = path[x][y]; // 遞歸的將 path[x][y] 上通過的第一個頂點放入 x 中,而後在下一個遞推中從 x 出發再遞歸處其它頂點; 53 } 54 55 if( x != -1 ) 56 { 57 ret.add(x); // 將最後的一個 x 加入返回值隊列中,由於上面 x == y,終止了在返回隊列中的加入,因此這裏要加入 58 } 59 } 60 else 61 { 62 THROW_EXCEPTION(InvalidParameterException, "Index <x, y> is invalid ..."); 63 } 64 65 /* 看看目標的兩個最短值之間是否真的有最短路徑 */ 66 if( ret.length() < 2 ) 67 { 68 THROW_EXCEPTION(ArithmeticException, "There is no path from x to y ..."); 69 } 70 71 return toArray(ret); 72 }
10,小結:
1,Floyd 算法經過遞推逐步求得全部頂點間的最短路徑;
2,Floyd 算法的本質是經過中轉頂點尋找更短的路徑;
3,鄰接矩陣是最短路徑推導的起始矩陣;
4,路徑矩陣記錄了最短路徑上的各個頂點;