在刷題的過程當中經常會遇到求最短路徑的問題,在求無權圖的問題中咱們經常使用BFS來求其最短路徑,而BFS沒法解決網(有權圖)中的問題,咱們解決網中的最短路徑經常使用dijkstra算法來求解。java
dijkstra算法是一種貪心的思想,具體其正確性的證實,這裏就再也不贅述。下面來直接講解如何使用dijkstra算法:算法
1.咱們在使用dijkstra算法時爲了其編寫的便捷性通常使用鄰接矩陣來描述一個圖。並將鄰接矩陣中每一個元素的值初始化爲無窮大(或者很大很大的值)。以後根據圖中的結構加入數字,稱這個矩陣爲E[][]。以下:ui
2.接下來咱們還須要3個矩陣,分別爲dist[] , collected[] , path[] 。dist用來存放遍歷節點的距離信息,初始化爲所求節點到其餘各點的距離信息;collected[]用來存放是否dist中收錄過該節點,初始化爲false ;path[]用來存放路徑,初始化爲-1 。spa
3. dijkstra算法的具體過程的僞代碼以下:翻譯
public void dijkstra(boolean collected[],int[] dist,int[][] E,int[] path) { while(1) { v = collected[]爲false的點中dist[]值最小的頂點; if(v不存在) break ; collected[v] = true ; for(v頂點的每一個鄰接點w) if(collected[w] == false) { if(dist[v] + E[v][w] < dist[w]) { dist[w] = dist[v] + E[v][w] ; path[w] = v ; } } } }
以上爲dijkstra算法的基本過程,下面選一道dijkstra算法的題目來具體解釋一下:code
PAT1003blog
As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.three
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.ci
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.input
5 6 0 2 1 2 1 5 3 0 1 1 0 2 2 0 3 1 1 2 1 2 4 1 3 4 1
2 4
(你們本身翻譯吧……)
這道題目很明顯是要求咱們求出有多少種距離相同的最短路徑,同時他還要求一個最多的人員數
完整代碼以下:
import java.util.*; public class Main { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); int cities = scanner.nextInt(); int roads = scanner.nextInt(); int start = scanner.nextInt(); int end = scanner.nextInt(); int[] dis = new int[cities]; int[][] map = new int[roads][roads]; boolean[] set = new boolean[cities]; int[] weigh = new int[cities] ; int[] w = new int[cities]; int[] num = new int[cities] ; for(int i = 0 ; i < cities ; i ++) { Arrays.fill(map[i], 9999999); } Arrays.fill(dis, 9999999); for(int i = 0 ; i < cities ; i ++) { weigh[i] = scanner.nextInt(); } for(int i = 0 ; i < roads ; i ++) { int x = scanner.nextInt(); int y = scanner.nextInt(); int z = scanner.nextInt(); map[x][y] = map[y][x] = z; } scanner.close(); dis[start] = 0 ; w[start] = weigh[start] ; num[start] = 1 ; for(int i = 0 ; i < cities ; i ++) { int index = -1 ; int min = 9999999; for(int j = 0 ; j < cities ; j ++) { if(set[j] == false && dis[j] < min) { min = dis[j]; index = j ; } } if(index == -1) break ; set[index] = true ; for(int j = 0 ; j < cities ; j ++) { if(set[j] == false && map[index][j] != 9999999) { if(min + map[index][j] < dis[j]) { dis[j] = min + map[index][j] ; num[j] = num[index] ; w[j] = w[index] + weigh[j] ; } else if(min + map[index][j] == dis[j]) { num[j] = num[j] + num[index] ; if(w[index] + weigh[j] > w[j]) { w[j] = w[index] + weigh[j] ; } } } } } System.out.print(num[end] + " " + w[end]); } }
下面咱們來逐步分析:
1.讀取數據以及構建鄰接矩陣:
Scanner scanner = new Scanner(System.in); int cities = scanner.nextInt(); int roads = scanner.nextInt(); int start = scanner.nextInt(); int end = scanner.nextInt(); int[] dis = new int[cities]; //構建dist[] int[][] map = new int[roads][roads]; //鄰接矩陣E boolean[] set = new boolean[cities]; //collected[] int[] weigh = new int[cities] ; //記錄每一個城市救援隊的數目 int[] w = new int[cities]; //到達每一個城市的救援隊的最多數量 int[] num = new int[cities] ; //相同距離有多少種走法 for(int i = 0 ; i < cities ; i ++) //初始化鄰接矩陣 { Arrays.fill(map[i], 9999999); } Arrays.fill(dis, 9999999); for(int i = 0 ; i < cities ; i ++) //初始化每一個城市的救援隊 { weigh[i] = scanner.nextInt(); } for(int i = 0 ; i < roads ; i ++) //記錄鄰接矩陣 { int x = scanner.nextInt(); int y = scanner.nextInt(); int z = scanner.nextInt(); map[x][y] = map[y][x] = z; } scanner.close();
2.使用dijkstra算法求最短路徑:
dis[start] = 0 ; //起點到七點的距離爲0 w[start] = weigh[start] ; num[start] = 1 ; //初始化起點的走法有一種 for(int i = 0 ; i < cities ; i ++) { int index = -1 ; int min = 9999999; for(int j = 0 ; j < cities ; j ++) { if(set[j] == false && dis[j] < min) //尋找dist[]中沒有被收錄的最小元素 { min = dis[j]; index = j ; } } if(index == -1) break ; //若是沒有最小元素,則說明最短路徑已經尋找完畢 set[index] = true ; //collected[]設置爲true 表示已經收錄該節點 for(int j = 0 ; j < cities ; j ++) //查找v相鄰元素的距離 { if(set[j] == false && map[index][j] != 9999999) { if(min + map[index][j] < dis[j]) { dis[j] = min + map[index][j] ; //更新最短距離 num[j] = num[index] ; //更新走法 w[j] = w[index] + weigh[j] ; //記錄最短距離的救援隊的數目 } else if(min + map[index][j] == dis[j]) //當最短距離相同時 { num[j] = num[j] + num[index] ; //距離相同時,更新走法 if(w[index] + weigh[j] > w[j]) { w[j] = w[index] + weigh[j] ; //距離相同時救援隊記錄最多的那個 } } } } }