最短路径问题(单源+多源)

Dijkstra简介:

迪杰斯特拉算法(Dijkstra)是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止
注意该算法要求图中不存在负权边。

核心思想:

找离自己相邻的最近的点,更新距离,重复操作。

其实这和人的思维方式有些相似。

模拟过程更利于理解

在理解Dijkstra的基础上,我们可以用
Dijkstra可解决以下几种最短路问题:

  1. 单源最短路问题(一个起点到一个终点 )
  2. 延伸到—>任意起点到终点
  3. 多源最短路问题( 多起点多终点

单源问题
例如:
Dijkstra求最短路I–>简单入门的模板

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

如果路径不存在,则输出 −1。

数据范围
1≤n≤500,
1≤m≤105,
图中涉及边长均不超过10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

模板,直接记。

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 510;int n, m;
int g[N][N];
int dist[N];
bool st[N];int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < n - 1; i ++ ){int t = -1;for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}int main()
{scanf("%d%d", &n, &m);memset(g, 0x3f, sizeof g);while (m -- ){int a, b, c;scanf("%d%d%d", &a, &b, &c);g[a][b] = min(g[a][b], c);}printf("%d\n", dijkstra());return 0;
}

自问自答:
int t = -1;
t 是用来干嘛的?
t 是用来找临近的最近的点的。

这是朴素版的Dijkstra的算法,适用于稠密图。

那稀疏图怎么办?
堆优化版的Dijkstra!

Dijkstra求最短路 II–>优化版

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值。 请你求出 1 号点到 n 号点的最短距离,如果无法从 1
号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。 接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。 如果路径不存在,则输出 −1。

数据范围
1≤n,m≤1.5×105,
图中涉及边长均不小于 0,且不超过 10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e6+10;
typedef pair<int,int> PII;
int n,m;
int e[N],ne[N],h[N],idx;
int w[N],dist[N];
bool st[N];
void add(int a,int b,int c)
{w[idx]=c;e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}int Dijkstra()
{memset(dist,0x3f,sizeof dist);dist[1]=0;priority_queue<PII,vector<PII>,greater<PII>> heap;//小根堆heap.push({0,1}); //第一个元素存距离,第二个元素存点while(heap.size()){auto t=heap.top();heap.pop();int ver=t.second;if(st[ver]) continue;st[ver]=true;for(int i=h[ver];i!=-1;i=ne[i]){int j=e[i];if(dist[j] > dist[ver] + w[i]){dist[j] =dist[ver] + w[i];heap.push({dist[j],j});}}}if(dist[n]==0x3f3f3f3f) return -1;return dist[n];
}
int main()
{memset(h,-1,sizeof h);cin>>n>>m;while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c);}cout<<Dijkstra();return 0;
}

搜索一次使用好像不太够,能不能多次搜索?
上例题!
畅通工程续–> 开工!

某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

Input

本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

Sample Input

3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2

Sample Output

2
-1

代码如下:

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 510;int n, m;
int x, y;
int g[N][N];
int dist[N];
bool st[N];void dijkstra()
{memset(dist, 0x3f, sizeof dist);memset(st, false, sizeof st);  //搜索前初始化,就可多次搜索dist[x] = 0;for (int i = 0; i <= n-1; i ++ ){int t = -1;for (int j = 0; j <= n-1; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;for (int j = 0; j <= n-1; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[y] == 0x3f3f3f3f)  dist[y] =-1;
}int main()
{while( scanf("%d%d",&n,&m) ! = EOF ){memset(g, 0x3f, sizeof g);while (m -- ){int a, b, c;scanf("%d%d%d", &a, &b, &c);g[a][b] = g[b][a] = min(g[a][b], c);}cin>> x >> y;dijkstra();printf("%d\n", dist[y]);}return 0;
}

能不能多次搜索关键在于处理st[ ](初始化为 false)。因为st[ ]用来判断相邻的点是否搜过,标记当前的状态,所以一次搜索过后想要再次搜索,只要把st[ ]初始化即可。

单源问题已解决,那多源问题怎么解决?
多源问题( 多起点多终点

初学者遇到多源问题可能会很茫然,认为会很复杂,其实很简单,看下面的例题就懂了。

一个人的旅行 -->来一场说走就走的旅行

虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中
会遇见很多人(白马王子,0),很多事,还能丰富自己的阅历,还可以看美丽的风景……草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女……眼看寒假就快到了,这么一大段时间,可不能浪费啊,一定要给自己好好的放个假,可是也不能荒废了训练啊,所以草儿决定在要在最短的时间去一个自己想去的地方!因为草儿的家在一个小镇上,没有火车经过,所以她只能去邻近的城市坐火车(好可怜啊~)。

Input

输入数据有多组,每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个,草儿想去的地方有D个;
接着有T行,每行有三个整数a,b,time,表示a,b城市之间的车程是time小时;(1=<(a,b)<=1000;a,b
之间可能有多条路) 接着的第T+1行有S个数,表示和草儿家相连的城市; 接着的第T+2行有D个数,表示草儿想去地方。

Output

输出草儿能去某个喜欢的城市的最短时间。

Sample Input

6 2 3
1 3 5
1 4 7
2 8 12
3 8 4
4 9 12
9 10 2
1 2
8 9 10

Sample Output

9

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1200;
const int MAX = 0x3f3f3f3f;
int t, s, d;
int g[N][N], dist[N], f[N], w[N];
bool st[N];
int dijkstra(int x)
{memset(st, false, sizeof st);memset(dist,0x3f,sizeof dist); dist[x] = 0;for(int i = 0; i < N; i++){int t=-1;for(int j = 0; j < N; j++)if(!st[j] && (t==-1 || dist[t] > dist[j] ))t = j;st[t] = true;for(int j = 0; j < N; j++)dist[j] = min( dist[j] , g[t][j] + dist[t] );}int res = MAX;for(int i = 0; i < d; i++)res = min( res, dist[w[i]] );  //找当前起点到所有终点的最短距离return res;
}
int main()
{while(scanf("%d%d%d", &t, &s, &d) != EOF){memset(g,0x3f,sizeof g);int x, y, time;for(int i = 0; i < t; i++){scanf("%d%d%d", &x, &y, &time);g[x][y] = g[y][x] = min(g[x][y],time);}for(int i = 0; i < s; i++)scanf("%d", &f[i]);for(int i = 0; i < d; i++)scanf("%d", &w[i]);int rmin = MAX;for(int i = 0; i < s; i++)rmin = min(rmin, dijkstra(f[i]));//输入一个起点就得到所有终点的最短距离,把所有起点输入,就得到离终点的最短距离printf("%d\n", rmin);}return 0;
}

看完后是不是发现只加了几行代码,就有不一样的效果!
Dijkstra搜索一次顺便求出一个起点到多终点的最短距离,多次搜索便可得出最短距离。

个人认为Dijkstra多源最短路的解决方法是:将多起点到多终点拆分成两步。

  1. 求单个起点到所有终点的最短距离;
  2. 遍历所有起点,记录最小的距离;

用Dijkstra大多数情况下用于解决单源最短路,少数情况下解决多源最短路。

不足之处,请指正。
欢迎点赞与评论~
记得收藏

最短路径问题(Dijkstra常用用法总结)相关推荐

  1. 最短路径问题----Dijkstra算法的解释

    先上图: 现在要找到地点V1到其余各个地点的最短路径(图中数字的单位默认为km.).有一个原则是:永远找最小,确保无更小. 第一步:v1->v1,v1->v2,...v1->v7的距 ...

  2. 最短路径(Dijkstra、Bellman-Ford和SPFA算法)

    最短路径(Dijkstra.Bellman-Ford和SPFA算法) 前言 图的存储方式 邻接矩阵 邻接表 链表建立 利用vector 结构体 核心思路 Dijkstra算法 图解 基本思想 求解步骤 ...

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

    最短路径问题 最短路径问题 1.最短路径问题介绍 2.Dijkstra 算法思路 3.Dijkstra算法示例演示 4.Dijkstra算法的代码实现(c++) 参考 最短路径问题 1.最短路径问题介 ...

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

    最短路径问题 最短路径问题 1.最短路径问题介绍 2.Dijkstra 算法思路 3.Dijkstra算法示例演示 4.Dijkstra算法的代码实现(c++) 参考 最短路径问题 1.最短路径问题介 ...

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

    前言 Nobody can go back and start a new beginning,but anyone can start today and make a new ending. Na ...

  6. 最短路径算法——Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson,无一幸免

    文章出自:http://dsqiu.iteye.com/blog/1689163 最短路径算法--Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson,无一幸免 本 ...

  7. C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)

    上一篇主要讲了二叉树的先序,中序,后序遍历算法以及深度和节点的算法,这篇就讲一讲图的基本算法. 一.图的基本概念 1.1有向图G1: 有向图G是由两个集合V(G)和E(G)组成的,其中:V(G)是顶点 ...

  8. 最短路径的Dijkstra算法(邻接表)

    原文:http://blog.csdn.net/axiqia/article/details/50984464 描述 以邻接表作为存储结构实现,求解从给定源点到给定结束点的最短路径. 输入 从1开始表 ...

  9. 图的单源最短路径:Dijkstra算法实现

    本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法 ...

最新文章

  1. java切面类整合_SpringBoot2.x【五】整合AOP切面编程
  2. 如何安装python虚拟环境_如何安装python3.9以及python虚拟环境?
  3. 二维指针动态分配内存连续问题分析
  4. 介绍一个能将任意关键字高亮实现的 Visual Studio Code 扩展
  5. php 面试靠快速排序,搞定PHP面试 - 常见排序算法及PHP实现
  6. Java-WAS的Hello world
  7. win10+ubuntu双系统安装方案
  8. android 朋友圈弹出框,Android popupwidown 实现朋友圈评论弹窗显示在软键盘上面
  9. 最新声鉴卡H5网页源码_完整可运转,引流专用神器
  10. 拆 米家台灯_米家台灯Pro测评:色彩还原力接近阳光,支持米家与HomeKit
  11. 计算机海报大赛策划书,海报策划书模板.docx
  12. 名人博客阅读摘要三:外部排序
  13. c 语言drawtext字体旋转,C# GDI+文字画图 添加任意角度文字(文字旋转是中心旋转,角度顺时针为正)...
  14. 如何将旧电脑数据迁移到新电脑?10 款数据迁移软件工具分享
  15. 桌面、平板、手机和机器人操作系统(ROS)市场占有率数据和趋势分享(附引用2019版)
  16. A Game of Thrones(33)
  17. 你可知,图像处理的回眸女郎是何方神圣?
  18. 最新最全的校园跳蚤小程序,二手商城小程序,二手书城小程序,带五星评分功能,发布商品,模糊搜索,评论,校园论坛功能
  19. 最近最开心的一件事情
  20. 渗透测试php靶场,渗透测试靶场初体验

热门文章

  1. 用UDP实现简易的聊天室
  2. AD9361配置(1)
  3. jQuery按钮切页样式
  4. CreatorPrimer | 飞机大战(一)
  5. OpenAI baseline GAIL代码讲解及其可视化
  6. 计算机制作效果图常用软件有,计算机园林效果图有哪些绘制过程?
  7. margin-top不起作用???
  8. 数字图像处理(1)——绪论
  9. 健康和食品行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  10. 【WLAN】【测试】Linux下aircrack-ng的应用之破解WPA/WPA2、WEP密钥