图论 (七) 最短路径算法【Dijkstra算法】

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/86657106

现实生活中,我们常常会面临者对路径选择的决策问题。例如来到一个陌生的城市,面对着纷繁交错的地铁网图,该如何进行选择可能成为一个大问题。

了解如何计算图的最短路径可能带来更为便捷的选择方式。对于非网图来说,由于没有权值,所谓的最短路径其实就是指两顶点之间经过的边数最少的路径;而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。显然,研究网图的最短路径更有实际意义。

求网图的最短路径有两种方式,分别是 D i j k s t r a Dijkstra 算法和 F l o y d Floyd 算法。

Dijkstra算法

在这里插入图片描述
算法思想:以起始点为中心向外层层扩展,直到扩展到终点为止。就比如说我们要求 a > e a->e 的最短路径,我们是一步步求出两个顶点之间顶点的最短路径,例如先把 a > e a->e 或者 a > g a->g 的最短路径求出,基于这个已求出的最短路径,求出该点到e的最短路径.

算法实现过程

(1) 一个完整的图(邻接矩阵) m a p map ,一个 p a t h path 数组存储路径(该顶点最短路径的前驱),一个 c o s t cost 数组存储对应的顶点最短路径,一个 f i n a l final 数组标记该顶点是否已求最短路径

(2) 首先进行初始化, f i n a l final 数组除源点外都初始化为0表示都未求, c o s t cost 数组初始化为源点的邻接矩阵行即 m a p [ 0 ] [ i ] map[0][i] ; p a t h path 数组都初始化为0

(3) 然后开始循环,共循环 n 1 n-1 次,分别对应源点到各个顶点的最短路径;通过比较 m i n min c o s t [ i ] cost[i] 的大小找到离源点最近的顶点,下标为 k k ;通过比较 m i n + m a p [ k ] [ j ] min + map[k][j] c o s t [ j ] cost[j] 的大小来更新当前的最短路径,即 c o s t [ j ] cost[j] = m i n ( m i n + m a p [ k ] [ j ] , c o s t [ j ] ) min(min + map[k][j], cost[j]) ;
p a t h [ j ] = k ; path[j] = k;

(4) 继续第三步的步骤,直到找完所有的最短路径为止

算法实现

直接根据上面的实现过程具体实现

(1) 准备:

#define MAXVEX 100
#define INFINITY 65535
int path[MAXVEX];
int cost[MAXVEX];
int map[MAXVEX][MAXVEX];

(2) 初始化操作:

	int i, j, k, min;
	int final[MAXVEX];  //标记顶点
	for (i = 0; i < n; ++i) {
		final[i] = 0;
		cost[i] = map[start][i]; //start表示源点下标
		path[i] = 0;
		cost[0] = 0;
		final[start] = 1;
	}

(3) 关键步骤:

	for (i = 1; i < n; ++i) {
		min = INFINITY;
		//找到v0到vk的最短路径
		for (j = 0; j < n; ++j) {
			if (!final[j] && cost[j] < min) {
				k = j;
				min = cost[j];
			}
		}
		final[k] = 1;  //标记该顶点
		//修正当前最短路径及距离
		for (j = 0; j < n; ++j) {
			if (!final[j] && min + map[k][j] < cost[j]) {
				cost[j] = min + map[k][j];
				path[j] = k;
			} 
		}
	}

(4) 完整实现:

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

#define MAXVEX 100
#define INFINITY 65535
int path[MAXVEX];
int cost[MAXVEX];
int map[MAXVEX][MAXVEX];
char vex[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' };

void Dijkstra(int map[][MAXVEX], int start, int n) {
	int i, j, k, min;
	int final[MAXVEX];
	for (i = 0; i < n; ++i) {
		final[i] = 0;
		cost[i] = map[start][i];
		path[i] = 0;
		cost[0] = 0;
		final[start] = 1;
	}
	for (i = 1; i < n; ++i) {
		min = INFINITY;
		//找到v0到vk的最短路径
		for (j = 0; j < n; ++j) {
			if (!final[j] && cost[j] < min) {
				k = j;
				min = cost[j];
			}
		}
		final[k] = 1;
		//修正当前最短路径及距离
		for (j = 0; j < n; ++j) {
			if (!final[j] && min + map[k][j] < cost[j]) {
				cost[j] = min + map[k][j];
				path[j] = k;
			} 
		}
	}
}

int main() {
	int n,m;
	int i,j,k,costvalue;
	ifstream in("input.txt");
	in >> n >> m;
	//构建图
	for (i = 0; i < n; ++i) {
		for (j = 0; j < n; ++j) {
			map[i][j] = INFINITY;
		}
	}

	for (k = 0; k < m; ++k) {
		in >> i >> j >> costvalue;
		map[i][j] = costvalue;
		map[j][i] = costvalue;
	}

	Dijkstra(map, 0, n);
	//打印最短路径
	for (i = 1; i < n; ++i) {
		if (path[i] == 0) {
			cout << vex[0] << "->" << vex[i] << "=" << cost[i] << endl;
		}
		else {
			vector<int> vec(n, 0);
			int t = 0;
			int k = i;	
			while (path[k] != 0) {
				vec[t] = k;
				k = path[k];
				++t;
			}
			vec[t] = k;
			++t;
			for (int l = t; l > 0 ; --l) {
				cout << vex[vec[l]] << "->";
			}
			cout << vex[vec[0]] << "=" << cost[i] << endl;
		}
	}
	return 0;
}

i n p u t . t x t input.txt

9 15
0 1 10
0 5 11
1 2 18
1 6 12
1 7 12
2 3 22
2 7 8
3 4 20
3 6 24
3 7 21
3 8 16
4 5 26
4 8 7
5 6 17
6 8 19

o u t p u t output

a->b=10
a->b->c=28
a->b->h->d=43
a->f->e=37
a->f=11
a->b->g=22
a->b->h=22
a->b->g->i=41


通过 D i j k s t r a Dijkstra 算法可以解决从某个源点到其余各个顶点的最短路径问题。从循环嵌套可以得到此算法的时间复杂度为 O ( n 2 ) O(n^2)

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/86657106
今日推荐