Dijkstra算法初探,但是很详细

下面我简称Dijkstra算法为D算法。D算法是在图中求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径,直到求出点源到其他各个节点的最短路径。那D算法的基本思想是什么呢?将节点设为一个集合V,再将集合V划为两部分S和V-S。S集合中的节点的最短路径已经确定,V-S中的节点的最短路径待定。

假设我们有下面这个图(画的有点拉):

从源点出发只经过S中的节点到达V-S的路径称为特殊路径。D算法的贪心策略就是选择最短的特殊路径长度dist[t],将节点t加入集合S中,同时更新数组dist。

我们正式梳理一下算法的过程即出现的变量。

1,设定G[][]为邻接矩阵存图,数组dist[i]记录从源节点到节点i的最短路径长度,如果没有则赋值无穷INF。p[i]记录最短路径上的节点i的之直接前驱。用一个bool型数组flag[i]判断节点i在哪一个集合,如果在S则flag[i]=true,否则为false(二进制表示)。

 

2,初始化。假设u为源节点,令集合S=u,对V-S集合中的节点i初始化为dist[i]=G[u][i](横向来看,就直接等于边权w),如果源节点u到节点i有边相连,初始化p[i]=u,否则p[i]=-1。

3,找最小路径在V-S集合中。dist[]最小的节点t就是V-S集合中距离源点u最近的节点,并将节点加入集合S。

4,松弛操作*。对V-S里的所有节点j,看是否可以借助t得到更短的路径。如果有,即表达式:dist[j]>dist[t]+G[t][j],那么进行操作更新dist[j]=dist[t]+G[t][j],并记录j的直接前驱为t,即p[j]=t。画个图演示一下啊:::

一开始是u->j的路径,但后来发现u->t->j更短,那就进行所谓的松弛操作。 

知道怎么做了,我们演示一遍。

先在2,3节点里面比较dist数组(度)的大小,发现2节点的度最小,放进去。

 之后在与2相连的4,3节点里面找。先看4,4的直接前驱t是2,所以更改dist[4]数组INF为8(从节点1加到节点4,但必须经过节点2)。之后看3,重复上述操作改dist[3]为4,那么联系上面的松弛操作,1->2->3的度小于(必须是小于才行)1->3的度,改改改!p[3]=2。现在与2相邻的节点的度计算完了,那就找最小的了,那必然是1->2->3,把节点3纳入集合S,之后重复上述操作。

下面是更改之后的数据:

 这里我在给出全部走完一遍的数据:::

 现在是要啥有啥就差代码了。

#include<iostream>
#define N 10000
#define INF 0x3f3f3f3f
using namespace std;
int G[N][N], dist[N], n, m;
int p[N];
bool flag[N];
void dij(int u)
{
	int i, j;
	for (i = 1; i <= n; i++)//初始化啊
	{
		dist[i] = G[u][i];
		flag[i] = false;
		if (dist[i] == INF)
			p[i] = -1;
		else
			p[i] = u;
	}
	dist[u] = 0;
	flag[u] = true;
	for (i = 1; i < n; i++)//找最小度的操作,n-1次
	{
		int temp = INF, t = u;//临时变量
		for (j = 1; j <= n; j++)
		{
			if (!flag[j] && dist[j] < temp)
			{
				temp = dist[j];
				t = j;
			}
		}
		if (t == u)
			return;
		flag[t] = true;
		for (j = 1; j <= n; j++)//判断是否可以松弛
		{
			if (!flag[j] && dist[j] > dist[t] + G[t][j])
			{
				dist[j] = dist[t] + G[t][j];//更新最短距离
				p[j] = t;//记录前驱
			}
		}
	}
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Dijkstra算法是一种用于解决单源最短路径问题的经典算法。它通过逐步确定从起点到其他节点的最短路径,并逐步扩展这些路径,直到达到目标节点或者所有可达节点都被处理。 以下是Dijkstra算法的伪代码: 1. 初始化: - 创建一个空的最短路径集合,用于存储已经确定最短路径的节点。 - 创建一个距离集合,用于存储从起点到每个节点的当前最短路径距离。初始时,除了起点,其他节点的距离均为无穷大。 - 将起点的距离设置为0。 2. 重复以下步骤,直到所有节点都被处理: - 在距离集合中选择一个未被处理的节点u,使得从起点到u的距离最小。 - 将节点u标记为已处理。 - 对于节点u的每个邻居节点v,如果从起点经过u再到达v的距离小于当前记录的最短路径距离,则更新距离集合中v的距离为新的最短路径距离。 3. 返回距离集合,其中包含从起点到每个节点的最短路径距离。 下面是对Dijkstra算法详细解释: - 第1步中的初始化是为了准备算法数据结构。最短路径集合用于存储已经确定最短路径的节点,距离集合用于存储从起点到每个节点的当前最短路径距离。初始时,所有节点的距离都被设置为无穷大,表示起点到这些节点的距离未知。 - 第2步是Dijkstra算法的核心部分。在每次迭代中,从距离集合中选择一个未被处理的节点u,使得从起点到u的距离最小。然后将节点u标记为已处理,并更新其邻居节点的最短路径距离。 - 第3步是算法的结束条件。当所有节点都被处理时,算法终止,并返回距离集合,其中包含了从起点到每个节点的最短路径距离。 总结起来,Dijkstra算法通过逐步确定从起点到其他节点的最短路径,并不断更新最短路径距离,直到达到目标节点或者所有可达节点都被处理。这个算法在解决单源最短路径问题中非常有效,但是对于含有负权边的图则无法正确工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值