2021/3/26 Dijkstra最短路径算法(代码量少、未使用类)

本文依据“街区最短路径”这一问题讲解并实现Dijkstra算法(未建立类,代码量较少)
参考博文:最短路径问题—Dijkstra算法详解

最短路径问题—Dijkstra算法详解
算法特点:

迪科斯彻算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。

算法的思路

Dijkstra算法采用的是一种贪心的策略,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T,初始时,原点 s 的路径权重被赋为 0 (dis[s] = 0)。若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为w(s, m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大。初始时,集合T只有顶点s。
然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中,OK,此时完成一个顶点,
然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。
然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点。

3、Dijkstra算法示例演示
下面我求下图,从顶点v1到其他各个顶点的最短路径

在这里插入图片描述

首先第一步,我们先声明一个dis数组,该数组初始化的值为:
在这里插入图片描述

我们的顶点集T的初始化为:T={v1}

既然是求 v1顶点到其余各个顶点的最短路程,那就先找一个离 1 号顶点最近的顶点。通过数组 dis 可知当前离v1顶点最近是 v3顶点。当选择了 2 号顶点后,dis[2](下标从0开始)的值就已经从“估计值”变为了“确定值”,即 v1顶点到 v3顶点的最短路程就是当前 dis[2]值。将V3加入到T中。
为什么呢?因为目前离 v1顶点最近的是 v3顶点,并且这个图所有的边都是正数,那么肯定不可能通过第三个顶点中转,使得 v1顶点到 v3顶点的路程进一步缩短了。因为 v1顶点到其它顶点的路程肯定没有 v1到 v3顶点短.

OK,既然确定了一个顶点的最短路径,下面我们就要根据这个新入的顶点V3会有出度,发现以v3 为弧尾的有: < v3,v4 >,那么我们看看路径:v1–v3–v4的长度是否比v1–v4短,其实这个已经是很明显的了,因为dis[3]代表的就是v1–v4的长度为无穷大,而v1–v3–v4的长度为:10+50=60,所以更新dis[3]的值,得到如下结果:
在这里插入图片描述

因此 dis[3]要更新为 60。这个过程有个专业术语叫做“松弛”。即 v1顶点到 v4顶点的路程即 dis[3],通过 < v3,v4> 这条边松弛成功。这便是 Dijkstra 算法的主要思想:通过“边”来松弛v1顶点到其余各个顶点的路程。

然后,我们又从除dis[2]和dis[0]外的其他值中寻找最小值,发现dis[4]的值最小,通过之前是解释的原理,可以知道v1到v5的最短距离就是dis[4]的值,然后,我们把v5加入到集合T中,然后,考虑v5的出度是否会影响我们的数组dis的值,v5有两条出度:< v5,v4>和 < v5,v6>,然后我们发现:v1–v5–v4的长度为:50,而dis[3]的值为60,所以我们要更新dis[3]的值.另外,v1-v5-v6的长度为:90,而dis[5]为100,所以我们需要更新dis[5]的值。更新后的dis数组如下图:

在这里插入图片描述

然后,继续从dis中选择未确定的顶点的值中选择一个最小的值,发现dis[3]的值是最小的,所以把v4加入到集合T中,此时集合T={v1,v3,v5,v4},然后,考虑v4的出度是否会影响我们的数组dis的值,v4有一条出度:< v4,v6>,然后我们发现:v1–v5–v4–v6的长度为:60,而dis[5]的值为90,所以我们要更新dis[5]的值,更新后的dis数组如下图:
在这里插入图片描述

然后,我们使用同样原理,分别确定了v6和v2的最短路径,最后dis的数组的值如下:
在这里插入图片描述
【例题】

最短路径
【问题描述】N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离
【输入形式】第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路接下来M行两个整数,表示相连的两个城市的编号
【输出形式】N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。
【样例输入】
4 4
1 2
2 3
1 3
0 1
【样例输出】
8
9
11

【代码思路】

/*
4 4
1 2
2 3
1 3
0 1
*/
#include <iostream>
#include <string.h>
#include <cmath>
using namespace std;

int Graph[10000][10000];
int edge_num;
int vertex_num;
int dis[10000];//用于记录最短路径长度 
int flag_dis[10000];//用于标记该点是否已被确定 
int MAX=0x3f3f3f3f;//无穷大 
int nosort_num;//记录未排序的数的个数 
int MOD=100000;

void CreateGraph()
{
	for(int i=0;i<edge_num;i++)
	{
		int ver1,ver2,weight;
		cin>>ver1>>ver2;
		weight=(int)pow(2,i);
		Graph[ver1][ver2]=weight;
		Graph[ver2][ver1]=weight;
	}
}

int FindMindis()//在dis中找距离最小值的点 
{
	int i,min=9999;
	for(i=0;i<vertex_num;i++)
	{
		if(dis[i]<dis[min]&&flag_dis[i]==0&&dis[i]!=0)min=i;
	}
	flag_dis[min]=1;//将找到的最小距离点做标记,为了下次不参与查找 
	nosort_num--;
	return min;
}

void Dijkstra(int v)
{
	flag_dis[v]=1;
	//初始化dis数组
	for(int i=0;i<vertex_num;i++)
	{
		dis[i]=Graph[v][i];//v到其余定点的距离 
	} 
	
	while(nosort_num>1)
	{
		int min_dis=FindMindis();
		for(int i=0;i<vertex_num;i++)
		{
			if(Graph[min_dis][i]!=0&&Graph[min_dis][i]!=MAX)
			{
				dis[i]=min(dis[i],dis[min_dis]+Graph[min_dis][i]);
			}
		}
	} 
}

void PrintDis()
{
	for(int i=0;i<vertex_num;i++)
	{
		if(dis[i]!=0&&dis[i]!=MAX)
		cout<<dis[i]%MOD<<endl;
	}
}
int main()
{
	cin>>vertex_num>>edge_num;
	memset(Graph,MAX,sizeof(Graph));//初始化 
	memset(flag_dis,0,sizeof(flag_dis));
	memset(dis,MAX,sizeof(dis));
	nosort_num=vertex_num;
	for(int i=0;i<vertex_num;i++)//将自身点的距离初始化为0 
	{
		Graph[i][i]=0;
	}
	
	CreateGraph();
	Dijkstra(0);
	PrintDis();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yozu_Roo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值