Dijkstra算法原理及代码实现(c++版)

目录

 

1 算法简介

2 算法原理

1)初始化

2)循环体

3)进行一次循环

4)结束条件

3 代码实现

4 参考


1 算法简介

算法任务:求图G中一源点C其他所有点最短路径的算法

基本思路:将图G中的点(记为集合V)分为两部分,已找到最短路径的点集S与尚未找到最短路径的点集\overline{S}(=V-S)。按到源点C由近  到远的顺序,逐个将\overline{S}中离源点C最近的点加入点集S,直到将所有的点都加入S,算法完成。

使用条件:边权不为负的连通图(有向无向均可)

2 算法原理

问题描述:求下图(记为图G)从点V_{0}到其他点的最短路径(用dis[n]存储,n为图中点的总数,dis[i]代表点V_{i}V_{0}的最短路径除了dis[n]之外,还需要这定义这几个变量:

矩阵edge[n][n]:使用邻接表方式来存储带权图 ,数组visit[n]:记录点V_{i}是否已经找到最短路径(true表示已找到,false表示未找到)

解答步骤:按照初始化,循环体,结束条件三步进行描述,符合代码实现的要求

1)初始化

由于已经确定了源点是V_{0},那么现在可以初始化得到dis[0]=0,visit[0]=true

已找到最短路径的点集S中仅含V_{0}一个点(S={V_{0}}),此时\overline{S}中的点要与S中的点建立路径,只能通过与V_{0}相连。

V_{0}直接相连的点为V_{1}V_{2},则初始化的dis[n]={ 0 , 1 , 5 ,INF,INF,INF,INF,INF,INF}

2)循环体

首先将目前的dis[n]中距离最小的点加入点集S,目前S={V_{0}V_{1}},比起之前,我们多了一个S与\overline{S}之间点建立路径的中介:点V_{1}

然后更新dis[n],因为多了一个中介点,所以我们可以通过V_{0}\rightarrowV_{1}\rightarrow其他点来建立新的路径,与V_{1}直接相连的为V_{2}V_{3}V_{4},那么通过中介点V_{1},dis[n]={ 0 , 1 ,dis[1]+edge[1][2]=4 , dis[1]+edge[1][3]=8 ,dis[1]+edge[1][4]=6,INF,INF,INF,INF},再与上一步的dis[n]比较,dis[n]={ 0 , 1 , 5 ,INF,INF,INF,INF,INF,INF},比较这两个dis[n],保留相同点距离源点距离更小的那条路径。

则这一步更新得到的dis[n]={0 , 1 , 4,8,6,INF,INF,INF,INF}。

3)进行一次循环

首先将目前的dis[n]中距离最小的点加入点集S,目前S={V_{0}V_{1}V_{2}},比起之前,多了一个S与\overline{S}之间点建立路径的中介:点V_{2}

然后更新dis[n],只需要比较V_{0}\rightarrow其他点和通过V_{0}\rightarrowV_{2}\rightarrow其他点的路径,保留距离更小的路径即完成更新。

4)结束条件

点集S包含图G内的所有点。用上面已定义的变量表示就是visit[n]全部为true。

 

3 代码实现

#include<iostream>
using namespace std;
const int INF = 99999;
int main() {
	int edge[9][9] = {
			{ 0 , 1 , 5 ,INF,INF,INF,INF,INF,INF},
			{ 1 , 0 , 3 , 7 , 5 ,INF,INF,INF,INF},
			{ 5 , 3 , 0 ,INF, 1 , 7 ,INF,INF,INF},
			{INF, 7 ,INF, 0 , 2 ,INF, 3 ,INF,INF},
			{INF, 5 , 1 , 2 , 0 , 3 , 6 ,INF,INF},
			{INF,INF, 7 ,INF, 3 , 0 ,INF, 5 ,INF},
			{INF,INF,INF, 3 , 6 ,INF, 0 , 2 , 7 },
			{INF,INF,INF,INF, 9 , 5 , 2 , 0 , 4 },
			{INF,INF,INF,INF,INF,INF, 7 , 4 , 0 }
	};
	int dis[9]; fill(dis, dis + 9, INF);
	bool visit[9]; fill(visit, visit + 9, false);
	//对应步骤1):初始化
	int c1 = 0;
	dis[c1] = 0;

	//最外层循环对应步骤3):结束条件,把n个点均放入点集S
	for (int i = 0; i < 9; i++) {

		//这一层循环对应步骤2):循环体中的寻找当前dis[n]中距离最小的点加入点集S
		int mind = INF, u = -1;
		for (int j = 0; j < 9; j++) {
			if (visit[j] == false && dis[j] < mind) {
				u = j;
				mind = dis[j];
			}
		}
		if (u == -1) break;
		visit[u] = true;
		//这一层循环对应步骤2):循环体中的更新dis[n]步骤
		for (int v = 0; v < 9; v++) {
			if (visit[v] == false && edge[u][v] < INF) {
				if (dis[u] + edge[u][v] < dis[v]) {
					dis[v] = dis[u] + edge[u][v];
				}
			}
		}
	}
	for (int i = 0; i < 9; i++)
		cout << dis[i] << ' ';

	system("pause");
	return 0;
}

运行结果:

4 参考

示例图来源:

https://www.jianshu.com/p/b8734fd2ab57

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值