[算法] 最短路径-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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章