Dijkstra 主要思想 Dijkstra
算法用于计算图中一点到其它点的最短路径。
每次从剩余顶点中找到离源点最近的点,将这个点加入已确定最短路径的点集,然后更新其他未确定最短路径并且与这个点相邻的点到源点的最短距离。
与Prim算法比较 相同点:
计算过程类似于Prim算法 ,都是从一个顶点开始,逐步向外扩展。 不同点:
Prim算法 是根据剩余顶点与生成树之间的距离最小
来选取下一个点,而Dijkstra
算法是根据剩余顶点与源点之间的距离最小
。Prim算法 每次加入一点后就对所有剩余的点进行更新,而Dijkstra
算法只对未确定最短路并且与刚刚确定的点相邻的点
进行更新。代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 void Dijkstra (int n, float ** M, int v0, float dist[], int path[]) { bool * set = new bool [n]; int v; for (int i = 0 ; i < n; i++) { dist[i] = M[v0][i]; set [i] = false ; if (M[v0][i] < INF) { path[i] = v0; } else { path[i] = -1 ; } } set [v0] = true ; path[v0] = -1 ; for (int i = 0 ; i < n - 1 ; i++) { float min = INF; for (int j = 0 ; j < n; j++) { if (!set [i] && dist[j] < min) { v = j; min = dist[j]; } } set [v] = true ; for (int j = 0 ; j < n; j++) { if (!set [j] && dist[v] + M[v][j] < dist[j]) { dist[j] = dist[v] + M[v][j]; path[j] = v; } } } }
输出路径 最后得到的path[v]
保存的是v到源点的最短路径上的前一点u
,比如:
graph LR
v0((v0)) --> other((...)) --> u((u)) --> v((v))
对于源点v0,有path[v0]=-1
于是通过这个path[]
数组就可以递归地得到最短路径上的所有点:
1 2 3 4 5 6 7 8 9 10 void PrintPath (int path[], int v) { if (path[v] == -1 ) { printf ("%d " , v); } else { PrintPath(path, path[v]); printf ("-> %d " , v); } }
Floyd 主要思想 Floyd
算法用于计算图中所有点对之间的最短路径。
对于每个点v
,尝试加入到所有点对(i, j)
之间的路径上。如果从i
到j
的路径上加入顶点v
之后路径变短,也就是 \(A[i][v] + A[v][j] < A[i][j]\) ,其中A[][]
数组保存的是当前所有点对之间最短路径的长度。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void Floyd (int n, float ** M, int ** path) { std ::vector <std ::vector <int >> A(n, std ::vector <int >(n)); for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n; j++) { A[i][j] = M[i][j]; path[i][j] = -1 ; } } for (int v = 0 ; v < n; v++) { for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n; j++) { if (A[i][v] + A[v][j] < A[i][j]) { A[i][j] = A[i][v] + A[v][j]; path[i][j] = v; } } } } }
输出路径 最后得到的path[][]
保存的是点对之间路径上的一点,类似Dijkstra
算法得到的结果,可以递归输出。
1 2 3 4 5 6 7 8 9 10 11 void PrintPath (int ** path, int n, int u, int v) { if (path[u][v] == -1 ) { printf ("%d -> %d " , u, v); } else { int mid = path[u][v]; PrintPath(path, n, u, mid); PrintPath(path, n, mid, v); } }