Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。
原理:每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短
步骤如下:加权图 G,边的距离dis[][], 前驱节点记录path[][]
1:初始化 path[i][j] = j;即:初始化所有节点都是直接相连
2:遍历 G 的节点 n1 ,尝试 是否满足 存在两个节点 a,b 使: [a->b] > [a->n1->b], 如果存在那么 修改 dis[a][b] = dis[a][n1]+dis[n1][b] 和 path[a][b]=path[a][n1];(通俗的说就是,查找以当前点为中介点连接两点是否比两点之前的路径更短?)
public static void floyd(int[][] graph){
int size = graph.length;
int path[][] = new int[size][size];
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
path[i][j] = j;// 初始化所有节点都是直接相连的即都是 i到j 中间不间隔k
}
}
// 循环遍历每个节点是否有 i到k到j 比 i到j的距离小
for (int k = 0; k < size; k++){
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
// i到k到j 比 i到j的距离(也有可能是上一个i到k到j)小
// 记录下 新的 i到j 距离 即 i到k到j的距离
// 记录下 中转边
if (graph[i][k] != GraphUtils.MAX
&& graph[k][j] != GraphUtils.MAX
&& graph[i][k] + graph[k][j] < graph[i][j]){
// 记录最短距离
graph[i][j] = graph[i][k] + graph[k][j];
// 记录最短路径
// i到j 的第一个节点 肯定是 i到k 的第一个节点
// 这样 path[i][j] 就是 i-k 和 k-j的路径了
path[i][j] = path[i][k];
}
}
}
}
printDis(graph);
printLine(path, graph);
}
private static void printDis(int[][] graph){
int size = graph.length;
for (int n = 0; n < size; n++){
for (int i = 0; i < size; i++){
if (i != n && graph[n][i] != GraphUtils.MAX)
System.out.printf("%d -> %d:%d , ", n, i, graph[n][i]);
}
System.out.println();
}
}
private static void printLine(int[][] path, int[][] graph){
int size = path.length;
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
int x = i;
if (i == j || graph[x][j] == GraphUtils.MAX)
continue;
System.out.printf("from %d to %d: %d", i, j, i);
while (graph[x][j] != GraphUtils.MAX
&& path[x][j] != -1
&& path[x][j] != x){
System.out.printf(" -> %d", path[x][j]);
x = path[x][j];
}
System.out.println();
}
}
}