首页 > 编程语言 >最短路径问题---Dijkstra算法详解

最短路径问题---Dijkstra算法详解

时间:2022-10-06 16:58:42浏览次数:60  
标签:int 路径 算法 --- Dijkstra 详解 maxn 顶点 dis

0. 最短路径问题介绍

问题解释:

从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径

1. Dijkstra算法介绍

  • 算法特点:

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

  • 算法的思路

    Dijkstra算法采用的是一种贪心的策略

    需要声明一个数组 \(dis\) 以及一个集合 \(T\)

    \(dis[i]\) 表示源点到节点 \(i\) 的最短距离

    \(T\) 中存储已经找到了最短路径的节点

    初始时,源点 \(s\) 的路径权重被赋为 0 \((dis[s] = 0)\)。若对于节点 \(s\) 存在能直接到达的边 \(s \to m\),则把 \(dis[m]\) 设为 \(w\),同时把所有其他(\(s\) 不能直接到达的)节点的路径长度设为无穷大。初始时,集合 \(T\) 只有顶点 \(s\)。

    然后,从 \(dis\) 数组选择最小值,则该值就是源点 \(s\) 到该值对应的顶点的最短路径,并且把该点加入到 \(T\) 中,OK,此时完成一个顶点。

    接着我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比当前的最短路径短,如果是,那么就替换这些顶点在 \(dis\) 中的值。

    然后,又从 \(dis\) 中找出最小值,重复上述动作,直到 \(T\) 中包含了图的所有顶点。

3、Dijkstra算法示例演示

求下图,从顶点 \(v_1\) 到其他各个顶点的最短路径

首先第一步,我们先声明一个dis数组,该数组初始化的值为(下标从1开始):

下标 1 2 3 4 5 6
dis 0 10 30 100

我们的 \(T\) 的初始化为:\(T = \left\{v_1\right\}\)

既然是求 \(v_1\) 顶点到其余各个顶点的最短路程,就先找一个离 1 号顶点最近的顶点。通过数组 \(dis\) 可知当前离 \(v_1\) 顶点最近是 \(v_3\) 顶点。当选择了 2 号顶点后,\(dis[3]\) 的值就确定下来了,即 \(v_1\) 顶点到 \(v_3\) 顶点的最短路程就是当前 \(dis[3]\) 的值。将 \(v_3\) 加入到 \(T\) 中。

为什么呢?因为目前离 \(v_1\) 顶点最近的是 \(v_3\) 顶点,并且这个图所有的边都是正数,那么肯定不可能通过第三个顶点中转,使得 \(v_1\) 顶点到 \(v_3\) 顶点的路程进一步缩短了。因为 \(v_1\) 顶点到其它顶点的路程肯定没有 \(v_1\) 到 \(v_3\) 顶点短.

OK,既然确定了一个顶点的最短路径,下面我们就要根据这个新入的顶点 \(v_3\) 会有出度,发现 \(v_3\) 所连的边的有: \(v_3 \to v_4\),那么我们看看路径:\(v_1 \to v_3 \to v_4\) 的长度是否比 \(v_1 \to v_4\) 短,其实这个已经是很明显的了,因为 \(dis[3]\) 代表的就是 \(v_1 \to v_4\) 的长度为无穷大,而 \(v_1 \to v_3 \to v_4\) 的长度为:10+50=60,所以更新 \(dis[3]\) 的值,得到如下结果:

下标 1 2 3 4 5 6
dis 0 10 60 30 100

然后,我们又从除 \(dis[3]\) 和 \(dis[1]\) 外的其他值中寻找最小值,发现 \(dis[5]\) 的值最小,通过之前是解释的原理,可以知道 \(v_1\) 到 \(v_5\) 的最短距离就是 \(dis[5]\) 的值,然后,我们把 \(v_5\) 加入到集合 \(T\) 中,然后考虑 \(v_5\) 的出度是否会影响我们的数组 \(dis\) 的值,\(v_5\) 有两条出度:\(v_5 \to v_4\) 和 \(v_5 \to v_6\),然后我们发现:\(v_1 \to v_5 \to v_4\) 的长度为50,而 \(dis[4]\) 的值为60,所以我们要更新 \(dis[4]\) 的值。另外,\(v_1 \to v_5 \to v_6\) 的长度为90,而 \(dis[6]\) 为100,所以我们需要更新 \(dis[6]\) 的值。更新后的 \(dis\) 数组如下:

下标 1 2 3 4 5 6
dis 0 10 50 30 90

然后,继续从 \(dis\) 中选择未确定的顶点的值中选择一个最小的值,发现 \(dis[4]\) 的值是最小的,所以把 \(v_4\) 加入到集合 \(T\) 中,此时集合 \(T=\left\{ v_1,v_3,v_5,v_4 \right\}\),然后考虑 \(v_4\) 的出度是否会影响我们的数组 \(dis\) 的值,\(v_4\) 有一条出度:\(v_4 \to v_6\),然后我们发现 \(v_1 \to v_5 \to v_4 \to v_6\) 的长度为60,而 \(dis[6]\) 的值为90,所以我们要更新 \(dis[6]\) 的值,更新后的 \(dis\) 数组如下:

下标 1 2 3 4 5 6
dis 0 10 50 30 60

然后,我们使用同样原理,分别确定了 \(v_6\) 和 \(v_2\) 的最短路径,最后 \(dis\) 的数组的值如下:

下标 1 2 3 4 5 6
dis 0 10 50 30 60

因此,从图中,我们可以发现 \(v_1 \to v_2\) 的值为 \(∞\),代表没有路径从 \(v_1\) 到达 \(v_2\)。所以我们得到的最后的结果为:

4、Dijkstra算法代码实现:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=7010;
struct node{
	int i;
	int k;
	bool operator < (node a) const{
		return k>a.k;
	}
};
int n,m,s;
ll dis[maxn];
bool T[maxn];
priority_queue<node> q;
int head[maxn],to[2*maxn],nxt[2*maxn],w[2*maxn],cnt=1;
void add(int x,int y,int v){
	cnt++;
	to[cnt]=y;
	w[cnt]=v;
	nxt[cnt]=head[x];
	head[x]=cnt;
}
int main(){
	cin>>n>>m>>s;
	for(int i=1,x,y,v;i<=m;i++){
		cin>>x>>y>>v;
		add(x,y,v);
		add(y,x,v);
	}
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push(node{s,0});
	while(q.size()){
		node h=q.top();
		int p=h.i;
		q.pop();
		if(T[p]) continue;
		T[p]=true;
		for(int i=head[p];i;i=nxt[i]){
			if(dis[p]+w[i]<dis[to[i]]&&!T[to[i]]){
				dis[to[i]]=dis[p]+w[i];
				q.push(node{to[i],dis[to[i]]});
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(dis[i]==0x3f3f3f3f3f3f3f3f) printf("-1\n");
		else printf("%lld\n",dis[i]);
	}
	return 0;
}

标签:int,路径,算法,---,Dijkstra,详解,maxn,顶点,dis
From: https://www.cnblogs.com/ycw123/p/16757941.html

相关文章

  • pytest-allure相关
    安装mac安装allurebrewinstallalluer安装插件allure-pytestpip3installallure-pytest生成报告第一种方式pytesttest_01.py--alluredir=./report--cle......
  • Red Hat Enterprise Linux release 8.0 (Ootpa)-用户和组增删基本操作
    1、查看当前系统用户:[root@servera~]#grepbash/etc/passwd   或者[root@servera~]#cat/etc/passwd|grepbash或者:[root@servera~]#cut-d:-f1/e......
  • day10 -方法
    ##方法###方法的重载在一个类中有相同的函数名称,但是形参不同的函数 规则:1.方法名称必须相同2.参数列表必须不同(个数不同,类型不同,参数排列顺序不同)3.返回值类型......
  • 【算法-简单01】合并2个有序数列
    合并2个有序数列结果:时间复杂度:O(N)空间复杂度:O(N)比较抽象的点结论:Node对象有3个属性:Node本身、val,以及Node.nextNode本身判空,结合while来进行遍历查询val......
  • day10- 练习(计算器的实现)
    1publicstaticvoidmain(String[]args){2Scannerscanner=newScanner(System.in);3System.out.println("输入:");4intx=s......
  • 一种基于注意力的Few-Shot目标检测统一框架(附论文下载)
    公众号ID|ComputerVisionGzq学习群|扫码在主页获取加入方式论文地址:​​https://arxiv.org/pdf/2201.02052.pdf​​计算机视觉研究院专栏作者:Edison_GFew-Shot目标检测(FSOD)......
  • Spring-MVC原理
        DispactherServletDispactherServlet为整个SpringMVC的控制中心,用于接收拦截用于的请求原理1.浏览器向服务器发送请求,DispactherServlet拦截请求并调用处......
  • 思维飞梭-随笔
    软件技术基础第一次课程随笔作业目标自我介绍;练习写博客的操作姓名-学号谭延鑫-2020330301016一、自我介绍1、基本身份信息hey,这里是谭延鑫的第一次关......
  • C语言:随机数产生 指定范围内随机整数的产生:(a-b) (0-99)
    #include<stdio.h>main(){inta,b,c;for(a=1;a<110;a++)printf("%d",rand()%10);getchar();}第一次运行:  第二次运行:  结果相同......
  • java--while小练习和switch小练习
    while小练习动态录入学生个数,成绩,求总成绩和平均值packagelearnday2;importjava.util.Scanner;*@description:动态录入学生成绩,并求总分和平均值publicclasswhileDe......