求解城市之間的最短距離是一個非常實際的問題,其大意如下:
某地區由n個城市,如何選擇路線使某個城市到某個指定城市的的距離最短?
注意:這里需要求解的最短路徑指的是兩個城市之間的最短距離,而不是所有城市之間最短總距離。
1.最短路徑算法
//最短路徑算法 static void distMin(GraphMatrix GM,int vend){ //vend為結束點 int[] weight=new int[GraphMatrix.MaxNum]; //某終止點到各頂點的最短路徑長度 int i,j,k,min; vend--; for(i=0;i<GM.VertexNum;i++){ //初始化weight數組 weight[i]=GM.EdgeWeight[vend][i]; } for(i=0;i<GM.VertexNum;i++){ //初始化path數組 if(weight[i]<MaxValue&&weight[i]>0){ //有效權值 path[i]=vend; } } for(i=0;i<GM.VertexNum;i++){ //初始化tmpvertex數組 tmpvertex[i]=0; //初始化頂點集合為空 } tmpvertex[vend]=1; //選入頂點vend weight[vend]=0; for(i=0;i<GM.VertexNum;i++){ //查找未用頂點的最小權值 min=MaxValue; k=vend; for(j=0;j<GM.VertexNum;j++){ if(tmpvertex[j]==0&&weight[j]<min){ min=weight[j]; k=j; } } tmpvertex[k]=1; //將頂點k選入 for(j=0;j<GM.VertexNum;j++){ //以頂點k為中間點,重新計算權值 if(tmpvertex[j]==0&&weight[k]+GM.EdgeWeight[k][j]<weight[j]){ weight[j]=weight[k]+GM.EdgeWeight[k][j]; path[j]=k; } } } }
2.完整的程序代碼示例
package com.cn.datastruct; import java.util.Scanner; //最短路徑求解 public class DistMin { static class GraphMatrix{ static final int MaxNum=20; char[] Vertex=new char[MaxNum]; //保存頂點信息(序號或字母) int GType; //圖的類型(0:無向圖,1:有向圖) int VertexNum; //頂點的數量 int EdgeNum; //邊的數量 int[][] EdgeWeight=new int[MaxNum][MaxNum]; //保存邊的權 int[] isTrav=new int[MaxNum]; //遍歷標志 } static final int MaxValue=65535; //最大值(可設為一個最大整數) static int[] path=new int[GraphMatrix.MaxNum]; //兩點經過的頂點集合的數組 static int[] tmpvertex=new int[GraphMatrix.MaxNum]; //最短路徑的起始點集合 static Scanner input=new Scanner(System.in); //創建鄰接矩陣圖 static void CreateGraph(GraphMatrix GM){ int i,j,k; int weight; //權 char EstartV,EendV; //邊的起始頂點 System.out.printf("輸入圖中各頂點信息\n"); for(i=0;i<GM.VertexNum;i++){ //輸入頂點 System.out.printf("第%d個頂點:", i+1); GM.Vertex[i]=(input.next().toCharArray())[0]; //保存到各頂點的數組元素中 } System.out.printf("輸入構成各邊的頂點及權值:\n"); for(k=0;k<GM.EdgeNum;k++){ //輸入邊的信息 System.out.printf("第%d條邊:", k+1); EstartV=input.next().charAt(0); EendV=input.next().charAt(0); weight=input.nextInt(); for(i=0;EstartV!=GM.Vertex[i];i++); //在已有頂點中查找始點 for(j=0;EendV!=GM.Vertex[j];j++); //在已有的頂點中查找終點 GM.EdgeWeight[i][j]=weight; //對應位置保存權值,表示有一條邊 if(GM.GType==0){ //若是無向圖 GM.EdgeWeight[j][i]=weight; //在對角位置保存權值 } } } // 清空矩陣 static void ClearGraph(GraphMatrix GM) { int i, j; for (i = 0; i < GM.VertexNum; i++) { for (j = 0; j < GM.VertexNum; j++) { GM.EdgeWeight[i][j] = MaxValue; // 設置矩陣中各元素的值為MaxValue } } } // 輸出鄰接矩陣 static void OutGraph(GraphMatrix GM) { int i, j; for (j = 0; j < GM.VertexNum; j++) { System.out.printf("\t%c", GM.Vertex[j]); // 在第一行輸出頂點信息 } System.out.println(); for (i = 0; i < GM.VertexNum; i++) { System.out.printf("%c", GM.Vertex[i]); for (j = 0; j < GM.VertexNum; j++) { if (GM.EdgeWeight[i][j] == MaxValue) { // 若權值為最大值 System.out.printf("\tZ"); // 以Z表示無窮大 } else { System.out.printf("\t%d", GM.EdgeWeight[i][j]); // 輸出邊的權值 } } System.out.println(); } } //最短路徑算法 static void distMin(GraphMatrix GM,int vend){ //vend為結束點 int[] weight=new int[GraphMatrix.MaxNum]; //某終止點到各頂點的最短路徑長度 int i,j,k,min; vend--; for(i=0;i<GM.VertexNum;i++){ //初始化weight數組 weight[i]=GM.EdgeWeight[vend][i]; } for(i=0;i<GM.VertexNum;i++){ //初始化path數組 if(weight[i]<MaxValue&&weight[i]>0){ //有效權值 path[i]=vend; } } for(i=0;i<GM.VertexNum;i++){ //初始化tmpvertex數組 tmpvertex[i]=0; //初始化頂點集合為空 } tmpvertex[vend]=1; //選入頂點vend weight[vend]=0; for(i=0;i<GM.VertexNum;i++){ //查找未用頂點的最小權值 min=MaxValue; k=vend; for(j=0;j<GM.VertexNum;j++){ if(tmpvertex[j]==0&&weight[j]<min){ min=weight[j]; k=j; } } tmpvertex[k]=1; //將頂點k選入 for(j=0;j<GM.VertexNum;j++){ //以頂點k為中間點,重新計算權值 if(tmpvertex[j]==0&&weight[k]+GM.EdgeWeight[k][j]<weight[j]){ weight[j]=weight[k]+GM.EdgeWeight[k][j]; path[j]=k; } } } } public static void main(String[] args) { GraphMatrix GM=new GraphMatrix(); //定義保存鄰接表結構的圖 String go; int vend; int i,k; System.out.println("求解最短路徑問題!"); do{ System.out.print("請先輸入生成圖的類型:"); GM.GType=input.nextInt(); //圖的種類 System.out.print("請輸入圖的頂點數量:"); GM.VertexNum=input.nextInt(); //輸入圖中頂點數 System.out.print("請輸入圖的邊的數量:"); GM.EdgeNum=input.nextInt(); //輸入圖中邊數 ClearGraph(GM); //清空圖 CreateGraph(GM); //生成鄰接表結構的圖 System.out.print("\n請輸入結束點:"); vend=input.nextInt(); distMin(GM,vend); vend--; System.out.printf("\n個頂點到達頂點%c的最短路徑分別為(起始點-結束點):\n",GM.Vertex[vend]); for(i=0;i<GM.VertexNum;i++){ //輸出結果 if(tmpvertex[i]==1){ k=i; while(k!=vend){ System.out.printf("頂點%c-", GM.Vertex[k]); k=path[k]; } System.out.printf("頂點%c\n", GM.Vertex[k]); }else{ System.out.printf("%c-%c:無路徑\n", GM.Vertex[i],GM.Vertex[vend]); } } System.out.println("\n繼續玩嗎(y/n)?"); go=input.next(); }while(go.equalsIgnoreCase("y")); System.out.println("游戲結束!"); } }
程序運行結果如下:
求解最短路徑問題! 請先輸入生成圖的類型:0 請輸入圖的頂點數量:5 請輸入圖的邊的數量:6 輸入圖中各頂點信息 第1個頂點:1 第2個頂點:2 第3個頂點:3 第4個頂點:4 第5個頂點:5 輸入構成各邊的頂點及權值: 第1條邊:1 2 2 第2條邊:1 3 5 第3條邊:1 5 3 第4條邊:2 4 4 第5條邊:3 5 5 第6條邊:4 5 2 請輸入結束點:1 個頂點到達頂點1的最短路徑分別為(起始點-結束點): 頂點1 頂點2-頂點1 頂點3-頂點1 頂點4-頂點5-頂點1 頂點5-頂點1 繼續玩嗎(y/n)? n 游戲結束!
