最短路径问题-Dijkstra算法

Posted wcc-bugmaker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径问题-Dijkstra算法相关的知识,希望对你有一定的参考价值。

前言:

最短路径算法用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

最短路径问题是图论研究中的一个经典算法问题,是寻找图(由结点和路径组成的)中两结点之间的最短路径。

文章为了通俗易懂,避免使用一些复杂词汇,可能会丧失部分表述准确度,但是这样对我这样菜的新手更佳友好,文章介绍最为经典的Dijkstra算法。为了更好的描述算法增加可读性,将使用C++作为算法描述,而且不会考虑算法优化问题。

// 这一段是废话

迪杰斯特拉(Dijkstra)算法是典型的用来解决最短路径的算法,也是很多教程中的范例,由荷兰计算机科学家狄克斯特拉于1959年提出,用来求得从起始点到其他所有点最短路径。该算法采用了贪心的思想,每次都查找与该点距离最近的点,也因为这样,它不能用来解决存在负权边的图。解决的问题大多是这样的:有一个有向图G,边e的长度为l,找出第0点到第N点的最短路径。

 

问题描述:

技术分享图片

 

如图片为有向图,0点为出发点。

输入正整数N(0<N<=4)作为终点,请求出从0点到N点的最短路径长度。

 

分析:

我们读入数据就涉及“图”在计算机中的存储方式,这里给出两个最常用方案:

1.邻接矩阵

2.邻接表

为了简化这篇文章,只介绍方便的邻接矩阵存储方式。

邻接矩阵

邻接矩阵其实是一个二维数组。数组的每一个元素保存图中相邻两点之间的长度,数组两个下标分别表示对应两点的标号。

就比如题目中给出的图片,邻接矩阵是这样的:

int matrix[5][5] =

{

       { INF, 99, 50, INF, INF },

       { INF, INF, 50, 50, 50 },

       { INF, INF, INF, 99, INF },

       { INF, INF, INF, INF, 75 },

       { INF, INF, INF, INF, INF }

};
技术分享图片

 

图中共有5个点,所以数组大小为5x5。

比如0点到1点的距离为99,在邻接矩阵matrix中,表现为matrix[0][1] == 99;但是因为图为有向图,1点不能到0点,matrix[0][1] == INF。

INF表示两点之间距离无限远。而且因为一个点到一个点本身没有任何意义,所以一个点到自己的距离也设置为INF。

邻接矩阵基本上可以应付大部分的情况,但是你会发现,邻接矩阵在内存空间方面占用较多,文章给出的例子只有5个定点,需要5x5的int数组,如果点特别多,而且为有向图可以考虑使用邻接表的方式存储。

 

下面介绍Dijkstra算法的大致步骤:

 

我们首先创建两个数组,起名为visited 和distance。visited记录节点是否被访问过,distance保存起点到该点的最短路径。

(1)   初始化。除了起点,其他点都没有被访问过,把每个点到起点从矩阵读取的路径存到distance数组。

(2)   遍历所有没有访问过的点,找到当前distance中保存最近的路径的点k,标记该点为已访问。

(3)   遍历所有没有访问过的点,检查是起点到每个点近还是k点到每个点近,如果是后者,更新当前点distance,保存k距起点的距离加上k到每个点的距离。

(4)   重复2,3步骤,直到所有点访问完成。

#include <cstdio>

const int INF = 0x3f3f3f;

static int matrix[5][5] =
{
	{ INF, 99, 50, INF, INF },
	{ INF, INF, 50, 50, 50 },
	{ INF, INF, INF, 99, INF },
	{ INF, INF, INF, INF, 75 },
	{ INF, INF, INF, INF, INF } 
};

/// dest 是目的地点
///	
int Dijkstra(const int dest) {
	// 顶点的数量
	const int vertex_num = 5;

	// vis数组是访问标记数组,记录已经访问的顶点
	// dis数组保存起点到当前点的最短路径
	// 都加1是为了访问安全,防止编译器和运行时抽风
	bool vis[vertex_num + 1] = { 0 };
	int  dis[vertex_num + 1] = { 0 };

	// 初始化0点到各点的距离
	for (int i = 1; i < vertex_num; ++i)
		dis[i] = matrix[0][i];

	// 标记0点,表示已经访问过
	vis[0] = true;

	for (int i = 1; i < vertex_num; ++i) {
		// 查找最近的点
		int min = INF, k = 0;
		for (int j = 0; j < vertex_num; ++j) {
			if (! vis[j] && dis[j] < min) {
				min = dis[j];
				k = j;
			}
		}
		// 标记查找到的最近点
		vis[k] = true;

		// 判断是直接点0到点j短,还是经过点k到点j更短
		for (int j = 1; j < vertex_num; ++j) {
			if (! vis[j] && min + matrix[k][j] < dis[j]) {
				dis[j] = min + matrix[k][j];
			}
		}
	}

	return dis[dest];
}

int main() {
	int n;
	while (~scanf("%d", &n)) {
		printf("%d
", Dijkstra(n));
	}
	return 0;
}
技术分享图片
 

以上是关于最短路径问题-Dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章

最短路径算法(Dijkstra)

最短路径 - Dijkstra算法

最短路径 Dijkstra 算法为啥边上的权值非负阿?

图-最短路径-Dijkstra及其变种

单源最短路径Dijkstra算法的思想详细步骤代码

最短路径问题-Dijkstra(基于图的ADT)