[算法] 最短路徑-Dijkstra

Dijkstra算法–單源最短路徑

可計算一個圖中某一結點到任意結點的最短路徑。

它通過更新一維數組dis的數值來計算最短路徑長度,還可以通過使用一維數組parent來記錄到達結點i之前需要到達的結點parent[i](似鏈表)。

算法要點:

  1. 一個圖中有n個結點,結點值1 2 ... n,輸入一個起點結點s,則初始化dis[s] = 0(結點s到結點s的距離爲0),其他的結點idis[i] = inf(結點s到其他結點的距離爲無窮大)。

  2. 通過邊表e找到以s爲起點的結點到其他結點間的距離e[s][i],同時將s加入到已經找到了最短路徑的集合P,在此用映射mp[s]=1表示。若dis[i]>dis[s]+e[s][i],則更新dis[i]=dis[s]+e[s][i],此過程稱爲鬆弛(relax)。找到不屬於集合P的各結點中dis[i]最小的那個結點i(距離結點s最近的的結點),如果最小的dis[i]=inf,則不繼續計算;反之,將結點i作爲新的s進行計算。(這部分和參考書不完全一致)

  3. parent數組的長度和dis相同,任意結點i初始化爲parent[i]=-1,在計算最短路徑dis[i]的過程中更新parent[i]的數值。輸出路徑時注意數據結構及順序。

#include<iostream>
#include<vector>
#include<map>
using namespace std;

const int inf = 999999999;

int n, m;
vector<int> dis, parent;
vector<vector<int>> e;
map<int, int> mp;

void dijkstra(int s) {
	int min = inf, mindis = inf;
	mp[s] = 1;		// 已經找到了最短路徑的結點就標記爲1 
	for (int i = 1; i < n+1; i++) {
		if (mp[i] == 0) {	// 未標記過的結點 
			if (e[s][i] != inf && dis[i] > dis[s] + e[s][i]) {
				dis[i] = dis[s] + e[s][i];
				parent[i] = s;	
				if (mindis > dis[i]) {	//找到此次relax得到的最小dis 
					mindis = dis[i];
					min = i;
				}		
			}
		}
	}
	if (min == inf) {	// 此次沒有relax到任何邊 
		return;
	}
	dijkstra(min);
}

int main () {
	int t1, t2, t3, from, to;
	cin >> n >> m;
	e.resize(n+1, vector<int>(n+1));
	dis.resize(n+1);
	parent.resize(n+1);
	// 初始化 
	for (int i = 1; i < n+1; i++) {
		dis[i] = inf;
		parent[i] = -1;
		for (int j = 1; j < n+1; j++) {
			if (i == j) {
				e[i][j] = 0;
			} else {
				e[i][j] = inf;
			}
		}
	}
	for (int i = 0; i < m; i++) {
		cin >> t1 >> t2 >> t3;
		// 有向圖 
		e[t1][t2] = t3;
	}
	cout << "from:";
	cin >> from;	// 輸入起點結點
	dis[from] = 0;
	dijkstra(from);
	// dis數組 記錄了該起點到任意結點間的最短路徑長度 
	cout << "dis:\t";
	for (int i = 1; i < n+1; i++) {
		cout << dis[i] << " ";
	}
	// parent數組 記錄了到達結點i之前需要先到達的結點parent[i] 
	cout << endl << "parent:\t";
	for (int i = 1; i < n+1; i++) {
		cout << parent[i] << " ";
	}
	cout << endl << "to:";
	cin >> to;		// 輸入終點結點 
	// 輸出路徑 
	vector<int> path;
	while (parent[to] != -1) {	// 逆序遍歷 
		path.push_back(to);
		to = parent[to];
	}
	if (path.size() == 0) {	// 不可達 
		cout << "inaccessible";
		return 0;
	}
	path.push_back(from);
	cout << "path:\t";
	for (int i = path.size()-1; i >= 0; i--) {	// 輸出路徑 
		cout << path[i] << " ";
	}
	return 0;
}

input:

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
1
6

output:

dis:    0 1 8 4 13 17
parent: -1 1 4 2 3 5
path:   1 2 4 3 5 6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章