1. 程式人生 > >經典演算法之圖的最短路徑(一):Dijkstra演算法

經典演算法之圖的最短路徑(一):Dijkstra演算法

Dijkstra演算法可以說基本上每一本有講到圖的最短路徑的書上都會有的一個演算法,但基本上都是講原理和虛擬碼,今天自己用Java程式碼給實現了一下,記錄在此。

Dijkstra演算法只是解決某些圖的最短路徑問題,這些圖需要滿足以下條件:權值非負、有向圖。並且該演算法只適用於求單源點最短路徑,即起始點只是固定的某一個點,當然了,如果想求多源點最短路徑,多用幾次Dijkstra演算法也是能求出來的。

該演算法的原理就是:先處理源點,更新一下從源點到每個點的距離以及前結點資訊,完後源點放到“已處理”組,從“未處理”組再找一個距離起點最近的點,看下是否有些點的路徑在經過這個點後比原來的路徑更短了,如果是,那麼更新下距離以及前結點資訊,如果否,不作操作,完後此點也放入“已處理”組,迴圈直到所有點都處理完。下面上程式碼:(最終列印路徑的時候偷懶了一下沒有把路徑倒過來列印)

package classic;

import java.util.Scanner;

public class Dijkstra {

	public static int start = 0;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("輸入點和邊的數目:");
		int V = sc.nextInt();//總共有多少個點
		int E = sc.nextInt();//總共有多少個邊
		
		int[][] G = new int[V][V];//用來存放圖的資訊
		int[] d = new int[V];//用來存放從起點到每個點的最短路徑長度
		int[] pre = new int[V];//用來存放每個點在其最短路徑上的前一個結點
		boolean[] used = new boolean[V];
		
		System.out.println("依次輸入每條邊的起點、終點和權值:(點的編號從0開始)");
		for(int i=0; i<E; i++){
			G[sc.nextInt()][sc.nextInt()] = sc.nextInt();
		}

		for(int i=0; i<V; i++){//初始化d
			pre[i] = start;
			if(i==start){
				d[i] = 0;
				continue;
			}
			if(G[start][i]==0)
				d[i] = Integer.MAX_VALUE/E;
			else{
				d[i] = G[start][i];
			}	
		}

		int cur = 0;
		used[start] = true;

		while(cur<V){
			int minDis = Integer.MAX_VALUE/E;
			int minIndex = 0;
			for(int i=0; i<V; i++){//每次取d[i]最小的那個點
				if(!used[i] && d[i]<minDis){
					minDis = d[i];
					minIndex = i;
				}
			}
			used[minIndex] = true;
			for(int i=0; i<V; i++){
				if(G[minIndex][i]>0 && d[i]>d[minIndex]+G[minIndex][i]){
					d[i] = d[minIndex]+G[minIndex][i];
					pre[i] = minIndex;
				}
			}
			cur++;
		}
		for(int i=0; i<V; i++){
			System.out.println("起點"+start+"到點"+i+"的最短路徑長度為:"+d[i]);
			System.out.println("最短路徑為:");
			int curv = i;
			System.out.print(i+"<-");
			while(true){
				curv = pre[curv];
				if(curv == start)
					break;
				System.out.print(curv+"<-");
			}
			System.out.println(start);
		}
		sc.close();
	}
}