介紹
- 利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的算法
思路
- 遍歷所有地點(一層循環),判斷該地點是否可以讓 任意兩地(這里就需要另外兩層循環) 的距離更近,如果可以,記錄下這個更短的距離,順便保存路徑
- 保存路徑則按照保存第三地點名稱的思路,假如AB之間有C使之更近,則PATH[A][B]=C;而其它循環自然會處理PATH[A][C],PATH[C][B]的問題,==INF則表示再無第三地點使之更近
- 輸出路徑則按照遞歸的思想,直到兩個地點之間再無第三地點使之更近,遞歸結束
案例
鄰接矩陣.png
運行結果
--------------------------------------------------
初始化原始點到點距離矩陣:
--------------------------------------------------
0 2 6 4
-1 0 3 -1
7 -1 0 1
5 -1 12 0
--------------------------------------------------
經過 Floyed 算法處理之后的點到點最短距離矩陣:
--------------------------------------------------
0 2 5 4
9 0 3 4
6 8 0 1
5 7 10 0
--------------------------------------------------
[0->0] 的最短路徑為 :(0->0)
[0->1] 的最短路徑為 :(0->1)
[0->2] 的最短路徑為 :(0->1->2)
[0->3] 的最短路徑為 :(0->3)
[1->0] 的最短路徑為 :(1->2->0)
[1->1] 的最短路徑為 :(1->1)
[1->2] 的最短路徑為 :(1->2)
[1->3] 的最短路徑為 :(1->2->3)
[2->0] 的最短路徑為 :(2->3->0)
[2->1] 的最短路徑為 :(2->3->0->1)
[2->2] 的最短路徑為 :(2->2)
[2->3] 的最短路徑為 :(2->3)
[3->0] 的最短路徑為 :(3->0)
[3->1] 的最短路徑為 :(3->0->1)
[3->2] 的最短路徑為 :(3->0->2)
[3->3] 的最短路徑為 :(3->3)
--------------------------------------------------
核心算法
package krmao.algorithm.floyed;
public class Floyed {
public static final int INF = -1;//無窮大/不可達
public static void calculateByFloyedAlgorithm(final int[][] distanceMatrix, final int pathMatrix[][]) {
if (distanceMatrix != null) {
for (int k = 0; k < distanceMatrix.length; k++)
for (int i = 0; i < distanceMatrix.length; i++)
for (int j = 0; j < distanceMatrix.length; j++) {
if (distanceMatrix[i][k] != Floyed.INF && distanceMatrix[k][j] != Floyed.INF && (distanceMatrix[i][j] == -1 || (distanceMatrix[i][j] > distanceMatrix[i][k] + distanceMatrix[k][j]))) {
distanceMatrix[i][j] = distanceMatrix[i][k] + distanceMatrix[k][j];
if (pathMatrix[i][j] == INF)
pathMatrix[i][j] = k;
}
}
}
}
public static void printPath(final int[][] distanceMatrix, final int pathMatrix[][]) {
if (pathMatrix != null && distanceMatrix != null) {
for (int i = 0; i < pathMatrix.length; i++) {
for (int j = 0; j < pathMatrix.length; j++) {
System.out.print("\t[" + i + "->" + j + "] 的最短路徑為 :");
if (distanceMatrix[i][j] == INF) {
System.out.println("(不可達)");
} else {
System.out.print("(" + i + "->");
printPath(pathMatrix, i, j);
System.out.println(j + ")");
}
}
}
}
}
private static void printPath(int path[][], int i, int j) {//遞歸輸出路徑
if (path != null && path[i][j] != INF) {
printPath(path, i, path[i][j]);
System.out.printf("%d->", path[i][j]);
}
}
public static void printMatrix(final int[][] originalMatrix) {
if (originalMatrix != null) {
for (int[] itemMatrix : originalMatrix) {
for (int itemValue : itemMatrix)
System.out.printf("%6d", itemValue);
System.out.println();
}
}
}
}
單元測試
package krmao.algorithm.floyed.test;
import org.junit.Test;
import static krmao.algorithm.floyed.Floyed.INF;
public class FloyedTest {
@Test
public void testFloyed() {
int originalMatrix[][] = new int[][]{
{0, 2, 6, 4},
{INF, 0, 3, INF},
{7, INF, 0, 1},
{5, INF, 12, 0}
};
//記錄點到點之間 經過哪一個點(保存這個點的名字) 使得距離更近,初始值INF表示不經過別的點中轉
int pathMatrix[][] = new int[][]{
{INF, INF, INF, INF},
{INF, INF, INF, INF},
{INF, INF, INF, INF},
{INF, INF, INF, INF}
};
System.out.println("--------------------------------------------------");
System.out.println("\t初始化原始點到點距離矩陣:");
System.out.println("--------------------------------------------------");
krmao.algorithm.floyed.Floyed.printMatrix(originalMatrix);
krmao.algorithm.floyed.Floyed.calculateByFloyedAlgorithm(originalMatrix, pathMatrix);
System.out.println("--------------------------------------------------");
System.out.println("\t經過 Floyed 算法處理之后的點到點最短距離矩陣:");
System.out.println("--------------------------------------------------");
krmao.algorithm.floyed.Floyed.printMatrix(originalMatrix);
System.out.println("--------------------------------------------------");
krmao.algorithm.floyed.Floyed.printPath(originalMatrix, pathMatrix);
System.out.println("--------------------------------------------------");
}
}
參考
http://developer.51cto.com/art/201403/433874.htm
http://www.cnblogs.com/skywang12345/p/3711532.html