数据结构重读 - 所有点对最短路径(Floyd算法)

如果我们要求每一顶点对之间的最短路径,怎么做呢?

方法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

Leave a Reply

Your email address will not be published. Required fields are marked *