44-Floyd 算法
作者:互联网
1. 概述
- Floyd算法是一个经典的动态规划算法,是解决任意两点间的最短路径(称为多源最短路径问题)的一种算法
- 也可以正确处理有向图或负权的最短路径问题
- Dijkstra ~ Floyd
- Dijkstra算法
- 单源最短路径,计算图中某一个顶点到其他顶点的最短路径
- 选定一个顶点作为出发访问顶点,求出从出发访问顶点到其他顶点的最短路径
- Floyd算法
- 多源最短路径,计算图中各个顶点之间的最短路径
- 每一个顶点都是出发访问顶点,求出从每一个顶点到其他顶点的最短路径
- Dijkstra算法
2. 算法思想
- 从任意顶点 i 到任意顶点 j 的最短路径不外乎 2 种可能:
- 直接从顶点 i 到顶点 j
- 从顶点 i 经过若干个顶点 k 到顶点 j
- 所以,我们假设 arcs(i, j) 为顶点 i 到顶点 j 的最短路径的距离,对于每一个顶点 k,我们检查 arcs(i, k) + arcs(k, j) < arcs(i, j) 是否成立
- 如果成立,证明从顶点 i 经顶点 k 再到顶点 j 的路径比顶点 i 直接到顶点 j 的路径短,我们便设置 arcs(i, j) = arcs(i, k) + arcs(k, j)
- 这样一来,当我们遍历完所有顶点 k,arcs(i, j) 中记录的便是顶点 i 到顶点 j 的最短路径的距离
3. 算法分析
- 根据以往的经验,如果要让任意两个顶点(假设从顶点 a 到顶点 b )之间的距离变得更短,唯一的选择就是引入第 3 个顶点(顶点 k),并通过顶点 k 中转(a → k → b)才可能缩短顶点 a 到顶点 b 之间的距离
- 这时问题便分解为:求取某一个顶点 k,使得经过中转顶点 k 后,使得两点之间的距离可能变短,且还可能需要中转 两个或者多个顶点 才能使两点之间的距离变短
- 于是,延伸到一般问题:
- 当不经过任意第 3 个顶点时,其最短路径为初始路径,即下图中的邻接矩阵所示
- 当只允许经过 1 号顶点时,求两点之间的最短路径该如何求呢?
- 只需判断 arcs[i][1] + arcs[1][j] 是否比 arcs[i][j] 要小即可
- arcs[i][j] 表示的是从 i 号顶点到 j 号顶点之间的距离
- arcs[i][1] + arcs[1][j] 表示的是从 i 号顶点先到 1 号顶点,再从1号顶点到 j 号顶点的路程之和
举例
- 由于上述代码更新了两点之间经过 1 号顶点的最短距离 arcs[i][j],因此,数组中每两个顶点之间对应距离都是最短的
- 此时 arcs[i][j] 的结果已经保存了中转 1 号顶点时的最短路径,如果再继续并入 2 号顶点为中转顶点,则是任意两个顶点都经过中转顶点 1 号顶点和 2 号顶点的最短路径
更一般的,继续并入下一个中转顶点一直到 vexCount 个时,arcs[i][j] 的结果保存的就是整个图中两点之间的最短路径了 // DP!
4. 代码实现
public class FloydAlgorithm {
public static void main(String[] args) {
char[] vertexs = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
int[][] matrix = new int[vertexs.length][vertexs.length];
final int N = 65535; // 表示不可以连接
matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
Graph graph = new Graph(vertexs, matrix);
graph.show();
graph.floyd();
System.out.println();
graph.show();
}
}
class Graph {
int vCount;
char[] vertexs;
int[][] dis; // 保存距离
int[][] pre; // 保存前驱
public Graph(char[] vertexs, int[][] dis) {
super();
vCount = vertexs.length;
this.vertexs = vertexs;
this.dis = dis;
this.pre = new int[vCount][vCount];
for(int i = 0; i < vCount; i++)
for(int j = 0; j < vCount; j++)
pre[i][j] = i;
}
public void floyd() {
int len;
for(int k = 0; k < vCount; k++) // k: 中间顶点
for(int i = 0; i < vCount; i++) // i: 出发顶点
for(int j = 0; j < vCount; j++) { // j: 终点
len = dis[i][k] + dis[k][j];
if(dis[i][j] > len) {
dis[i][j] = len;
pre[i][j] = k;
}
}
}
public void show() {
System.out.print(" ");
for(int i = 0; i < vCount; i++)
System.out.printf("%8c ", vertexs[i]);
System.out.println();
for(int i = 0; i < vCount; i++) {
System.out.print(vertexs[i]+" ");
for(int j = 0; j < vCount; j++)
System.out.printf("%c(%5d) ", vertexs[pre[i][j]], dis[i][j]);
System.out.println();
}
}
}
标签:vCount,arcs,int,44,路径,算法,Floyd,顶点,vertexs 来源: https://www.cnblogs.com/liujiaqi1101/p/12489977.html