1. 程式人生 > 其它 >最短路徑問題-Floyd演算法

最短路徑問題-Floyd演算法

(多看幾遍吧-.-,記住就好了,爭取能自己寫出來)

具體步驟和圖解看這個:https://www.cnblogs.com/ssyfj/p/9495960.html

知識點:

1)Floyd演算法適用於APSP(All Pairs Shortest Paths,多源最短路徑),是一種動態規劃演算法,稠密圖效果最佳,邊權可正可負2)時間複雜度比較高O(n*3),不適合計算大量資料。

3)可以算出任意兩個節點之間的最短距離

4)無論是迪傑斯特拉演算法還是弗洛伊德演算法,對於有向圖,無向圖都是可以使用的。另外我們的最短路徑一般都是針對有環圖,無環圖使用拓撲排序可以獲得

5)弗洛伊德演算法是用來求所有頂點到所有頂點的時間複雜度。
1)弗洛伊德演算法定義了兩個二維矩陣:
矩陣D記錄頂點間的最小路徑 ;例如D[0][3]= 10,說明頂點0 到 3 的最短路徑為10。
矩陣P記錄頂點間最小路徑中的中轉點 ;例如P[0][3]= 1 說明,0 到 3的最短路徑軌跡為:0 -> 1 -> 3。
它通過3重迴圈,k為中轉點,v為起點,w為終點,迴圈比較D0[v][w] 和 D0[v][k] + D0[k][w] 最小值,如果D0[v][k] + D0[k][w] 為更小值,
則把D0[v][k] + D0[k][w] 覆蓋儲存在D1[v][w]中。
2)核心思想:D1[v][w] = min{D0[v][k] + D0[k][w],D0[v][w]}
【D0代表原來未更新前的資料,D1表示我們修改更新後的新的資料】
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "queue.h"

#define MAXVEX 100    //最大頂點數
#define INFINITY 65535    //用0表示∞

typedef char VertexType;    //頂點型別,字元型A,B,C,D...
typedef int
EdgeType; //邊上權值型別10,15,... //鄰接矩陣結構 typedef struct { VertexType vers[MAXVEX]; //頂點表 EdgeType arc[MAXVEX][MAXVEX]; //鄰接矩陣,可看作邊表 int numVertexes, numEdges; //圖中當前的頂點數和邊數 }MGraph; typedef int Dist[MAXVEX][MAXVEX]; //存放各個頂點到其餘頂點的最短路徑權值和 typedef int Path[MAXVEX][MAXVEX]; //存放各個頂點到其餘頂點前驅頂點位置 //建立鄰接矩陣 void CreateMGraph(MGraph* G); //顯示鄰接矩陣 void showGraph(MGraph G); void Floyd(MGraph G,Path* path,Dist* dist); void ShowDistAndPath(Path P, Dist D,int n); void Floyd(MGraph G, Path* path, Dist* dist) { int i,j,k; //初始化path和dist for (i = 0; i < G.numVertexes;i++) { for (j = 0; j < G.numVertexes;j++) { (*dist)[i][j] = G.arc[i][j]; (*path)[i][j] = j; //初始化為這個的一個好處就是自己到自己的路徑就是自己,我們不用修改 } } //使用弗洛伊德核心演算法,三層迴圈求解 for (k = 0; k < G.numVertexes;k++) { for (i = 0; i < G.numVertexes;i++) { for (j = 0; j < G.numVertexes;j++) { if ((*dist)[i][j]>((*dist)[i][k]+(*dist)[k][j])&&i!=j) { //將權值和更新,路徑也變為中轉點 (*dist)[i][j] = (*dist)[i][k] + (*dist)[k][j]; (*path)[i][j] = (*path)[i][k]; } } } } } void ShowDistAndPath(Path P, Dist D,int n) { int i, j; printf("Printf Dist:\n"); for (i = 0; i < n;i++) { for (j = 0; j < n; j++) { if (i==j) printf(" 0"); //需要將我們的無窮轉換一下再顯示 else printf("%5d", D[i][j]); } printf("\n"); } printf("Printf Path:\n"); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) printf("%5d", P[i][j]); printf("\n"); } } int main() { MGraph MG; CreateMGraph(&MG); showGraph(MG); Path path; Dist dist; Floyd(MG, &path, &dist); ShowDistAndPath(path, dist, MG.numVertexes); system("pause"); return 0; } //生成鄰接矩陣 void CreateMGraph(MGraph* G) { int i, j, k, w; G->numVertexes = 9; G->numEdges = 16; //讀入頂點資訊 G->vers[0] = 'A'; G->vers[1] = 'B'; G->vers[2] = 'C'; G->vers[3] = 'D'; G->vers[4] = 'E'; G->vers[5] = 'F'; G->vers[6] = 'G'; G->vers[7] = 'H'; G->vers[8] = 'I'; //getchar(); //可以獲取回車符 for (i = 0; i < G->numVertexes; i++) for (j = 0; j < G->numVertexes; j++) G->arc[i][j] = INFINITY; //鄰接矩陣初始化 //建立了有向鄰接矩陣 G->arc[0][1] = 1; G->arc[0][2] = 5; G->arc[1][2] = 3; G->arc[1][3] = 7; G->arc[1][4] = 5; G->arc[2][4] = 1; G->arc[2][5] = 7; G->arc[3][4] = 2; G->arc[3][6] = 3; G->arc[4][5] = 3; G->arc[4][6] = 6; G->arc[4][7] = 9; G->arc[5][7] = 5; G->arc[6][7] = 2; G->arc[6][8] = 7; G->arc[7][8] = 4; for (i = 0; i < G->numVertexes;i++) for (k = i; k < G->numVertexes;k++) G->arc[k][i] = G->arc[i][k]; } //顯示鄰接矩陣 void showGraph(MGraph G) { for (int i = 0; i < G.numVertexes; i++) { for (int j = 0; j < G.numVertexes; j++) { if (G.arc[i][j] != INFINITY) printf("%5d", G.arc[i][j]); else printf(" 0"); } printf("\n"); } }