?算法背景:
图中的A,B,C,D,E,F,G,代表7个村庄,边上的权值带表两村庄之间的距离,现在要从某一个村庄,例如G村庄,往另外几个村庄送邮件,问任意一村庄到其他各村庄的最短距离分别是多少?
思路:
该问题实际是求从任一顶点到其余顶点的最短距离,即多源顶点间的距离。可以用弗洛伊德算法求解。
floyd算法求最短距离:
算法思路:
当计算i到j之间的最短距离时,利用一个过渡顶点k,先求出i和k之间的距离,再加上k和j之间的距离,对比得出最短距离(动态规划思想)。图中任意两顶点间都通过过渡顶点计算。
floyd算法需要维护两个二维数组:(i和j均为顶点数组的索引)
- distance[i][j]:?保存第i个顶点和第j个顶点的最短距离。初始时为图的邻接数组值。
- prePath[i][j]:?保存第i个顶点到第j个顶点的前驱结点值。
核心代码:
算法分析:
floyd算法中有三层for,最外层为过渡结点,中间层为顶点,最内层为终点,算法复杂度为O(n3)。对稠密图求解最佳,运行一次便可得出所有顶点间的关系。
public void floyd() {
for(int k = 0; k < n;k++) {//记录中间结点的索引
for(int i = 0; i < n;i++) {//记录开始结点的索引
for(int j = 0; j < n;j++) {//记录结束结点的索引
int len = distance[i][k] + distance[k][j];//“过渡距离”
if(len < distance[i][j]) {
distance[i][j] = len;
prePath[i][j] = prePath[k][j];
}
}
}
}
}
java代码:
import java.util.*;
public class Floyd {
public static void main(String[] args) {
int INF = 0x3f3f3f3f;
char []vertex = {'A','B','C','D','E','F','G'};
int [][]edge = new int [][] {
{INF,5,7,INF,INF,INF,2},
{5,INF,INF,9,INF,INF,3},
{7,INF,INF,INF,8,INF,INF},
{INF,9,INF,INF,INF,4,INF},
{INF,INF,8,INF,INF,5,4},
{INF,INF,INF,4,5,INF,6},
{2,3,INF,INF,4,6,INF}
};
graph graph = new graph(vertex, edge);
graph.floyd();
graph.printMatrix();
graph.getAllPath();
}
}
class graph{
char vertex[];
int distance[][];
int prePath[][];
int n;//图中顶点的数量
public graph(char[] vertex, int[][] distance) {
this.vertex = vertex;
this.distance = distance;
n = vertex.length;
prePath = new int[n][n];
for(int i = 0; i < n;i++) {
Arrays.fill(prePath[i], i);
}
}
public void printMatrix() {
System.out.println("各顶点间的最短距离为:");
for(int i = 0; i < n;i++) {
for(int j = 0; j < n; j++) {
System.out.printf("(%c->%c:%d) ",vertex[i],vertex[j],distance[i][j]);
}
System.out.println();
}
}
public void floyd() {
for(int k = 0; k < n;k++) {//记录中间结点的索引
for(int i = 0; i < n;i++) {//记录开始结点的索引
for(int j = 0; j < n;j++) {//记录结束结点的索引
int len = distance[i][k] + distance[k][j];//“过渡距离”
if(len < distance[i][j]) {
distance[i][j] = len;
prePath[i][j] = prePath[k][j];
}
}
}
}
}
private void getPath(int start,int end) {//start为路径起点,end为终点
int []temp = new int[n];
int index = 0;
int t = end;
while(true) {
if(t == start || start == t)break;
temp[index++] = t;
t = prePath[start][t];
}
temp[index] = start;
System.out.printf("顶点%c到顶点%c的最短路径为:",vertex[start],vertex[end]);
for(int i = index; i >= 0;i--) {
System.out.printf("%c ",vertex[temp[i]]);
}
System.out.println();
}
public void getAllPath() {
System.out.println("\n所有顶点间最短路径如下:");
for(int i = 0; i < n;i++) {
for(int j = 0; j < n;j++) {
if(i == j)continue;
getPath(i, j);
}
System.out.println();
}
}
}
运行输出:
各顶点间的最短距离为:
(A->A:4) (A->B:5) (A->C:7) (A->D:12) (A->E:6) (A->F:8) (A->G:2)
(B->A:5) (B->B:6) (B->C:12) (B->D:9) (B->E:7) (B->F:9) (B->G:3)
(C->A:7) (C->B:12) (C->C:14) (C->D:17) (C->E:8) (C->F:13) (C->G:9)
(D->A:12) (D->B:9) (D->C:17) (D->D:8) (D->E:9) (D->F:4) (D->G:10)
(E->A:6) (E->B:7) (E->C:8) (E->D:9) (E->E:8) (E->F:5) (E->G:4)
(F->A:8) (F->B:9) (F->C:13) (F->D:4) (F->E:5) (F->F:8) (F->G:6)
(G->A:2) (G->B:3) (G->C:9) (G->D:10) (G->E:4) (G->F:6) (G->G:4)
所有顶点间最短路径如下:
顶点A到顶点B的最短路径为:A B
顶点A到顶点C的最短路径为:A C
顶点A到顶点D的最短路径为:A G F D
顶点A到顶点E的最短路径为:A G E
顶点A到顶点F的最短路径为:A G F
顶点A到顶点G的最短路径为:A G
顶点B到顶点A的最短路径为:B A
顶点B到顶点C的最短路径为:B A C
顶点B到顶点D的最短路径为:B D
顶点B到顶点E的最短路径为:B G E
顶点B到顶点F的最短路径为:B G F
顶点B到顶点G的最短路径为:B G
顶点C到顶点A的最短路径为:C A
顶点C到顶点B的最短路径为:C A B
顶点C到顶点D的最短路径为:C E F D
顶点C到顶点E的最短路径为:C E
顶点C到顶点F的最短路径为:C E F
顶点C到顶点G的最短路径为:C A G
顶点D到顶点A的最短路径为:D F G A
顶点D到顶点B的最短路径为:D B
顶点D到顶点C的最短路径为:D F E C
顶点D到顶点E的最短路径为:D F E
顶点D到顶点F的最短路径为:D F
顶点D到顶点G的最短路径为:D F G
顶点E到顶点A的最短路径为:E G A
顶点E到顶点B的最短路径为:E G B
顶点E到顶点C的最短路径为:E C
顶点E到顶点D的最短路径为:E F D
顶点E到顶点F的最短路径为:E F
顶点E到顶点G的最短路径为:E G
顶点F到顶点A的最短路径为:F G A
顶点F到顶点B的最短路径为:F G B
顶点F到顶点C的最短路径为:F E C
顶点F到顶点D的最短路径为:F D
顶点F到顶点E的最短路径为:F E
顶点F到顶点G的最短路径为:F G
顶点G到顶点A的最短路径为:G A
顶点G到顶点B的最短路径为:G B
顶点G到顶点C的最短路径为:G A C
顶点G到顶点D的最短路径为:G F D
顶点G到顶点E的最短路径为:G E
顶点G到顶点F的最短路径为:G F
|