首页 > 其他分享 >Dijkstra实现单源最短路

Dijkstra实现单源最短路

时间:2023-12-28 23:13:38浏览次数:43  
标签:dist int 短路 源点 单源 Dijkstra 顶点

Dijkstra算法求单源最短路

Dijkstra算法应用于求一个给定图的单个源点到其他各顶点的最短路。其中应用Dijkstra算法的图应满足如下条件

  • 图中没有负权边
  • 有向或者无向图都可以
  • 图中若有自环或者重边也可以(需要自己先筛选一下)

Dijkstra算法的核心就是从源点开始对各个顶点进行松弛操作,且每一次松弛选择出当前最优也就是离源点最小的路径(贪心),直到求出总体最小的路径。其贪心的正确性证明可以看这个AcWing 849. Dijkstra算法(含正确性证明) - AcWing

朴素的Dijkstra算法

所谓朴素的Dijkstra就是在寻找当前未收入最短路的最小顶点时采用最朴素的遍历操作来寻找,与后面采用堆来比较朴素。
实现Dijkstra的步骤如下

  1. 初始化dist数组为正无穷,且令dist[s] = 0;s代表源点,dist[k]表示k顶点到源点的距离。源点本身到自身距离为0,其他顶点尚未更新默认为正无穷。
  2. 遍历所有顶点,从未收入最短路(st[k] == false)且更新过(dist[k] != 0x3f3f3f3f)的顶点中找到到源点距离最小的点,即为v。
  3. 将v收入到最短路中(st[v] = true),使用v更新v的邻接点到源点的距离,当v的邻接点到源点的距离大于v到源点再到该点的距离时,更新。

实现代码如下
849. Dijkstra求最短路 I - AcWing题库

#include <iostream>
#include <cstring>
using namespace std;
const int N = 600;
int g[N][N],dist[N];	//g[N][N],图的存储,dist[N],各顶点到源点的距离
bool st[N];				//顶点是否已经收入最短路
int n;					//顶点个数
void Dijkstra(int v)// v - > 源点
{
	memset(dist, 0x3f, sizeof(dist));
	dist[v] = 0;
	for (int i = 0; i < n; i++) //一共n个顶点,最多做n次操作即可更新所有顶点
	{
		int tmp = -1;
		for (int j = 1; j <= n; j++)
		{
			if (!st[j] && (tmp == -1 || dist[tmp] > dist[j]))
				tmp = j;
		}	//从未收入且更新过的顶点中选取最小值。由于未更新的节点为正无穷,不用特别判断也会自动被覆盖
		st[tmp] = true;	//将上述顶点收入
		for (int j = 1; j <= n; j++)
		{
			if (g[tmp][j] != -1)//若为tmp的邻接点
			{
				dist[j] = min(dist[j], dist[tmp] + g[tmp][j]);
			}
		}
	}
}

int main()
{
	memset(g, -1, sizeof(g));
	int m;
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int x, y, z;
		cin >> x >> y >> z;
		g[x][y] = g[x][y] == -1 ? z : min(g[x][y], z);//若有重边,仅保留重边中较小的那条边
	}
	Dijkstra(1);
	cout << (dist[n] == 0x3f3f3f3f ? -1 : dist[n]);
	return 0;
}

几点细节

  1. 存储图的数组一般初始化为-1。
  2. 存储路径的数组初始化为无穷大,dist[源点] = 0;
  3. 若题目中说有重边,可以在建图时保留最小的一条边
堆优化的Dijkstra

可以看出朴素Dijkstra算法中寻找未收入的最小顶点这一步,每一次循环都要遍历一遍顶点,最坏要循环n次,也就是说这一步的时间复杂度为\(O(n^2)\)。
不妨重新审视这个操作。我们要求的只是寻找某个最小值的操作,因此可以使用小根堆这一数据结构来优化这个操作。对于n个顶点,求其最小值的时间复杂度为\(O(1)\),更新堆中的顶点的复杂度为\(O(logn)\),这样优化后的总时间复杂度为$$O(nlogn)$$

直接上代码
注意这里使用邻接表建图且STL实现的数据结构居多
850. Dijkstra求最短路 II - AcWing题库

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1e5 + 20;
typedef pair<int, int> PII;	//使用pair来存储顶点,first是该顶点的dist,second是该顶点的编号
vector<PII> g[N];
int dist[N];
bool st[N];
int n, m;
void Dijkstra(int v)
{
	memset(dist, -1, sizeof(dist));
	dist[v] = 0;
	priority_queue<PII, vector<PII>, greater<PII>>h;//建立小根堆的方法,优先队列默认大根堆
	h.push({ 0,v }); //将源点加入堆中。first为dist的目的是让其作为第一关键字进行排序
	while (!h.empty())	//结束条件为队列空,也就是所有顶点都出队了
	{
		auto tmp = h.top();//取出最小未收录的最小顶点
		h.pop();
		int seq = tmp.second, distance = tmp.first;
		if (st[seq]) continue;//若该顶点已经加入最短路,说明上述tmp是一个冗余元素,直接丢掉进入下一轮操作
		st[seq] = true; //标记为已经加入最短路
		for (int j = 0; j < g[seq].size(); j++)
		{
			int q = g[seq][j].first, p = g[seq][j].second;
			if (dist[q] > dist[seq] + p) // 若可以更新
			{
				dist[q] = dist[seq] + p; //更新
				h.push({ dist[q],q }); //加入更新队列中
			}
		}

	}
}
int main()
{
	cin >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int x, y, z;
		cin >> x >> y >> z;
		g[x].push_back({y,z}); //编号,边权
	}
	Dijkstra(1);
	cout << (dist[n] == 0x3f3f3f3f ? -1 : dist[n]);
	return 0;
}

标签:dist,int,短路,源点,单源,Dijkstra,顶点
From: https://www.cnblogs.com/CrescentWind/p/17933784.html

相关文章

  • 洛谷B3647 【模板】Floyd 题解 floyd算法 求 多源多汇最短路
    题目链接:https://www.luogu.com.cn/problem/B3647floyd算法:https://oi-wiki.org/graph/shortest-path/#floyd-算法示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=101;intn,m,f[maxn][maxn];intmain(){scanf("%d%d",&n......
  • P1339 [USACO09OCT] Heat Wave G 最短路入门题 Dijkstra/SPFA/Dijkstra+优先队列优化
    目录朴素的Dijkstra算法SPFA算法Dijkstra+优先队列优化题目链接:https://www.luogu.com.cn/problem/P1339题目大意:无向图有单源最短路。朴素的Dijkstra算法时间复杂度\(O(n^2)\)。#include<bits/stdc++.h>usingnamespacestd;constintmaxn=2505;structEdge......
  • 最短路计数
    前置知识最短路的一个很好的性质:从\(s\)到\(t\)的最短路上的一个节点\(k\),都满足\(s\)到\(k\)的路径是关于\(s\)单源最短路的最短路证明:反证法,假设\(s\)到\(k\)的路径不为最短路,但\(s\tok\tot\)为到\(t\)的最短路,那么\(s\tok\tot\)的路径一定不会比\(s\)到\(k\)的最......
  • 7-5 单源最短路径
    7-5单源最短路径请编写程序求给定正权有向图的单源最短路径长度。图中包含n个顶点,编号为0至n-1,以顶点0作为源点。输入格式:输入第一行为两个正整数n和e,分别表示图的顶点数和边数,其中n不超过20000,e不超过1000。接下来e行表示每条边的信息,每行为3个非负整数a、b、c,其中a和b表示......
  • 图论——最短路
    https://csacademy.com/app/graph_editor/https://riverhamster.gitee.io/app/graph_editor/注:时间复杂度分析中,假设\(n\lem\len^2\)最短路本质上是一种DP阶段:点状态:拆点决策:边最优子结构:最短路的任何子路径都一定是最短路无后效性:正权图中一定可以找到一种无后......
  • 使用OCCT构建两个面之间的最短路径
    查找两个面之间的最短面路径查找面的邻面。std::vector<TopoDS_Face>OCCTUtility::adjacentFace(TopoDS_Faceconst&face,std::optional<TopoDS_Shape>shape,std::optional<TopTools_IndexedDataMapOfShapeListOfShape>edgeMapFace){std::vector<TopoD......
  • dijkstra最短路
    给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。输入格式第一行包含整数 n 和 m。接下来 m行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y的......
  • 12.11 迪杰斯特拉方法实现最短路径(c++)
     今天通过自主学习,,对数据结构中的迪杰斯特拉方法实现最短路径进行了深造,让我学会了很多新的东西。首先是问题描述:用迪杰斯特拉算法实现有向网的最短路径输入格式:第一行输入有向网的顶点和边数,第二行输入各顶点值,用空格间隔,第三行开始输入各条边的两个点的及边上的权值,用空......
  • #P1009. 单源最短路
    模板代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e5+10;vector<pair<int,int>>a[N];intdis[N],vis[N];intn,m;voidspfa(){ for(inti=1;i<=n;i++)dis[i]=0x3f; queue<int>q; dis[1]=0; q.push(......
  • 12.2迪杰斯特拉方法实现最短路径
    掌握迪杰斯特拉方法设计文档 代码#include<iostream>usingnamespacestd;//迪杰特斯拉:邻接矩阵:一维数组+二维数组+点边数typedefintVexType;#defineMVNum100#defineMaxInt32767intS[MVNum],Path[MVNum],D[MVNum];//迪杰特斯拉的三个数组typedefstruct{......