如果我们要求每一顶点对之间的最短路径,怎么做呢?
方法1:对N个顶点,依次执行前面的Prim算法。
方法2:使用Floyd算法。
实际上,Floyd算法是动态规划(DP)算法。
原理很简单,我们假设dp[i][j]表示从顶点i到顶点j的最短路径,则dp[i][j] = min (dp[i][k]+dp[k][j], 0<=k<=nvexs)。
于是算法如下:
import java.util.LinkedList;
public class Floyd {
public void SetGraph(Graph g) {
this.g = g;
}
public void ShortPath() {
// Alloc dp array and load all arc data
int pre[][] = new int[g.vexs.length][];
int dp[][] = new int[g.vexs.length][];
for (int i = 0; i < g.vexs.length; i++) {
dp[i] = new int[g.vexs.length];
pre[i] = new int[g.vexs.length];
for (int j = 0; j < g.vexs.length; j++) {
dp[i][j] = g.matrix[i][j];
pre[i][j] = g.matrix[i][j];
if (dp[i][j] != Integer.MAX_VALUE) {
pre[i][j] = i;
} else {
pre[i][j] = -1;
}
}
}
// DP
for (int i = 0; i < g.vexs.length; i++) {
for (int j = 0; j < g.vexs.length; j++) {
// dp[i][j] = min(dp[i][k]+dp[k][j])
for (int k = 0; k < g.vexs.length; k++) {
if (dp[i][k] != Integer.MAX_VALUE
&& dp[k][j] != Integer.MAX_VALUE) {
if (dp[i][k] + dp[k][j] < dp[i][j]) {
dp[i][j] = dp[i][k] + dp[k][j];
pre[i][j] = pre[k][j];
}
}
}
}
}
// Print
LinkedList<Integer> stk = new LinkedList<Integer>();
for (int i = 0; i < g.vexs.length; i++) {
for (int j = 0; j < g.vexs.length; j++) {
if (i != j) {
System.out.format("%d -> %d short_path is %d\n", g.vexs[i],
g.vexs[j], dp[i][j]);
// Stack push
stk.push(j);
int tmp = j;
while (tmp != i) {
tmp = pre[i][tmp];
stk.push(tmp);
}
// Output
if (!stk.isEmpty()) {
System.out.format("%d", stk.pop());
}
while (!stk.isEmpty()) {
System.out.format("->%d", stk.pop());
}
System.out.println();
}
}
}
}
private Graph g = null;
public static void main(String[] args) {
Graph g = new Graph();
g.input();
Floyd fld = new Floyd();
fld.SetGraph(g);
fld.ShortPath();
}
}
关于图的读取和创建,我们借用之前Prim算法的Graph类,如下:
import java.util.Arrays;
import java.util.Scanner;
public class Graph {
public Graph() {
scan = new Scanner(System.in);
}
public void input() {
intput_vexs();
input_arcs();
}
private void intput_vexs() {
// Input vexs
int nvexs = 0;
System.out.println("Please enter n for vexs:");
if (scan.hasNextInt()) {
nvexs = scan.nextInt();
}
vexs = new int[nvexs];
for (int i = 0; i < nvexs; i++) {
System.out.println("Please enter a integer for vex(" + i + "):");
if (scan.hasNextInt()) {
vexs[i] = scan.nextInt();
}
}
}
private void input_arcs() {
// Input weight between vexs
int nvexs = vexs.length;
matrix = new int[nvexs][];
for (int i = 0; i < nvexs; i++) {
matrix[i] = new int[nvexs];
Arrays.fill(matrix[i], Integer.MAX_VALUE);
}
int narcs = 0;
int x = 0, y = 0, w = 0;
System.out.println("Please enter n for arcs:");
if (scan.hasNextInt()) {
narcs = scan.nextInt();
}
for (int i = 0; i < narcs; i++) {
System.out.println("Please enter x, y, w for arc(" + i + "):");
if (scan.hasNextInt()) {
x = scan.nextInt();
x = vex2i(x);
}
if (scan.hasNextInt()) {
y = scan.nextInt();
y = vex2i(y);
}
if (scan.hasNextInt()) {
w = scan.nextInt();
}
if (x == -1 || y == -1 || w <= 0) {
System.out.println("x or y or w invalid, please enter again:");
i--;
} else {
matrix[x][y] = w;
}
}
}
public int vex2i(int v) {
for (int i = 0; i < vexs.length; i++) {
if (v == vexs[i]) {
return i;
}
}
return -1;
}
public int[][] matrix = null;
public int[] vexs = null;
private Scanner scan = null;
public static void main(String[] args) {
Graph g = new Graph();
g.input();
System.out.println("vexs:");
for (int i = 0; i < g.vexs.length; i++) {
System.out.print(g.vexs[i] + " ");
}
System.out.println();
System.out.println("matrix:");
for (int i = 0; i < g.matrix.length; i++) {
for (int j = 0; j < g.matrix[i].length; j++) {
System.out.format("%11d ", g.matrix[i][j]);
}
System.out.println();
}
}
}
测试图:
测试输入:
3 0 1 2 5 0 1 4 1 0 6 0 2 11 2 0 3 1 2 2
输出:
0 -> 1 short_path is 4 0->1 0 -> 2 short_path is 6 0->1->2 1 -> 0 short_path is 5 1->2->0 1 -> 2 short_path is 2 1->2 2 -> 0 short_path is 3 2->0 2 -> 1 short_path is 7 2->0->1
