Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
把图用邻接矩阵G表示出来,如果从Vi到Vj有路可达,则G[i][j]=d,d表示该路的长度;否则G[i][j]=无穷大。定义一个矩阵D用来记录所插入点的信息,D[i][j]表示从Vi到Vj需要经过的点,初始化D[i][j]=j。把各个顶点插入图中,比较插点后的距离与原来的距离,G[i][j] = min( G[i][j], G[i][k]+G[k][j] ),如果G[i][j]的值变小,则D[i][j]=k。在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。
Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法,也要高于执行|V|次SPFA算法。
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
缺点:时间复杂度比较高,不适合计算大量数据。
import java.util.Arrays; public class FloydAlgorithm { public static void main(String[] args) { char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; //创建邻接矩阵 int[][] matrix = new int[vertex.length][vertex.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(matrix, vertex); graph.floyd(); graph.show(); } } class Graph { char[] vertex; //存放顶点 int[][] dis; //各个顶点到其它顶点的距离 int[][] pre; //到达各个顶点的前驱顶点 public Graph(int[][] dis,char[] vertex) { int length = vertex.length; this.vertex = new char[length]; System.arraycopy(vertex, 0, this.vertex, 0, vertex.length); this.dis = new int[length][length]; for (int i = 0; i < length; i++) { System.arraycopy(dis[i], 0, this.dis[i], 0, length); } this.pre= new int[length][length]; for (int i = 0; i < length; i++) { Arrays.fill(this.pre[i],i); } } /** * 显示结果 */ public void show() { for (int i = 0; i < dis.length; i++) { for (int j = 0; j < dis.length; j++) { System.out.print(pre[i][j] + "\t"); } System.out.println(); for (int k = 0; k < dis.length; k++) { System.out.print("(" + vertex[i] + "到" + vertex[k] + "的最短距离是:" + dis[i][k] + ")"); } System.out.println(); } } /** * 弗洛伊德算法 */ public void floyd() { int length; for (int i = 0; i < dis.length; i++) { for (int j = 0; j < dis.length; j++) { for (int k = 0; k < dis.length; k++) { length = dis[j][i] + dis[i][k]; if (length < dis[j][k]) { dis[j][k] = length; pre[j][k] = pre[i][k]; } } } } } }