文章目录

  • 第一类:单源最短路
    • 一 所有边权都是正数(Dijkstra)
      • 朴素版Dijkstra(稠密图)
      • 堆优化版Dijkstra(稀疏图)
    • 二 存在负权边(BF和SPFA)
  • 第二类:多源汇最短路(Floyd)

常见的最短路问题,假定边为m,顶点为n。

第一类:单源最短路

一个点到其他所有点的最短距离,比如:从1到n的最短路
单源最短路再分两种:

一 所有边权都是正数(Dijkstra)

两种算法:
朴素Dijkstra算法,时间复杂度O(n2)O(n^2)O(n2),和边的数量无关,适合于稠密图(边数很多,m和n2n^2n2是一个规模)。
堆优化的Dijstra算法。 时间复杂度O(mlogn)O(mlogn)O(mlogn),适合于稀疏图。
其中,n是图中点的数量,m是图中边的数量

Dijkstra算法的思想是基于贪心的,每次选择最短的路。

朴素Dijkstra算法步骤:

集合S表示已确定最短距离的点

1. dist[1]=0,dist[i]= INF  //初始化
2. for i: 1~nt  ⬅不在S中的距离最近的点S  ⬅ t用t更新其他点的距离
朴素版Dijkstra(稠密图)

Acwing849. 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

ac代码

#include<bits/stdc++.h>
using namespace std;
const int N=510;int m , n;
int g[N][N];bool st[N]; //该点是否确定最短路
int dist[N];//原点到各点的距离 int dijkstra(){memset(dist,0x3f3f3f,sizeof(dist)); //初始化距离无穷大dist[1] =0 ; //1号点初始化为0//迭代n次 for(int i=0;i<n;i++){//找最小值int t=-1;  //找到当前最小的值 用t来存,t=-1表示没找到 for(int j=1;j<=n;j++){if(!st[j]&&( t==-1 || dist[t] >dist[j] ))t=j;} //加到集合S中st[t]=true;//用t更新其他点的距离for(int j=1;j<=n;j++)dist[j]= min(dist[j],dist[t]+g[t][j]); } //如果不连通返回-1if(dist[n]>=0xffff) return -1;return dist[n]; }int main(){cin>>n>>m;memset(g,0x3f,sizeof g);while(m--){int a,b,c;cin>>a>>b>>c;g[a][b]=min(g[a][b],c);  //去除重边 }   int t=dijkstra();cout<<t<<endl;}
堆优化版Dijkstra(稀疏图)

acwing850. 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×1051≤n,m≤1.5×10^51≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。

输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3

分析:

这题是稀疏图,使用邻接表来存储。

ac代码

#include<bits/stdc++.h>
using namespace std;
const int Mn=1e9;const int N=1000000;typedef pair<int ,int > PII;bool st[N]; //是否确定最短路
int dist[N]; //最短距离
int n ,m;
//使用邻接表来存储图
int h[N]; // 头节点数组
int ne[N]; //next指针指向的地址,这里是结点b的地址
int e[N]; //next指针指向的具体的值,这里是结点b
int w[N]; // a到b的边的权重
int idx; //索引//加边  a后面加b,权重是c
void add(int a,int b,int c){e[idx]=b,w[idx]=c,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}); //距离为0,编号为1 之所以距离放前面,是因为heap按照第一关键字排序while(heap.size()){//找最小点auto t=heap.top();heap.pop();int ver =t.second, distance = t.first;  //ver是编号,distance 是距离if(st[ver]) continue;//找到最小值st[ver]=true; //用当前点更新其他点//遍历当前 点ver的相邻的点for(int i=h[ver];i!=-1;i = ne[i]){int j=e[i]; //点if(dist[j]> distance + w[i]){dist[j]= distance +w[i];heap.push({dist[j],j});}}}if(dist[n]>=Mn) return -1;return dist[n];}int main(){cin>>n>>m;memset(h ,-1 ,sizeof h);  //头结点数组初始化为-1while(m--){int a , b, c;cin>>a>>b>>c;add(a,b,c);  //邻接表}int t=dijkstra();cout<<t<<endl;}

二 存在负权边(BF和SPFA)

两种算法:假定边为m,顶点为n
Bellman-Ford算法 ,时间复杂度O(nm)O(nm)O(nm),适合于边数不超过k条(此处k为限定的边数)。

算法思路:

  1. 扫描所有边(x, y, z),这里指的是从x到y,边权为z的边 ,如果dist[y] > dist[x] + z, 则用dist[x] + z 更新dist[y].
  2. 重复上述步骤,直到没有更新操作发生。

而spfa算法呢,在国际上通常称为”队列优化的Bellman-Ford算法“。它是对Bellman-Ford算法的优化,一般而言,我们刷题用的多的还是spfa。

SPFA算法 一般情况下比Bellman-Ford快,时间复杂度O(m)O(m)O(m),最坏O(nm)O(nm)O(nm),适合于负权边

spfa算法流程:

  1. 建立一个队列,最初队列中只含有起点1
  2. 取出队头结点x,扫描它的所有出边(x, y, z),如果dist[y] > dist[x] + z, 则用dist[x] + z 更新dist[y].同时, 若y不在队列中,则把y入队。
  3. 重复上述步骤,直到队列为空。

851. spfa求最短路

来源:acwing

  1. spfa代码和堆优化dijkstra很像。只不过spfa用的是队列queue。关于queue的操作,取出队头元素是front();存入元素是push().当然建图同样是邻接表。
  2. spfa算法中st数组的含义是:某个点是否已经在队列中。

spfa算法模板代码

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N  = 1e5 + 10;
int n, m;
int h[N],ne[N],w[N],e[N], idx;
typedef pair<int,int> PII;int dist[N];
bool st[N]; // st数组存的是当前这个点是否在队列中void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a] ,h[a] = idx ++;
}int spfa(){memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1); // 把1号点放进队列st[1] = true; while(q.size()){int t  = q.front();q.pop();st[t] = false; // 从队列中出来for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > dist[t] + w[i] ){dist[j] = dist[t] + w[i];if(!st[j]){ // 如果不在队列中,则加入到队列中q.push(j);st[j] = true;}}}}if(dist[n] == 0x3f3f3f3f) return -1;return dist[n];}int main(){cin >> n >> m;memset(h, -1, sizeof h);while(m --){int a, b, c;cin >> a >> b >> c;add(a, b ,c );}int t = spfa();if( t == -1) puts("impossible");else cout << t << endl;}

补充手写队列的spfa写法:

int spfa(){memset(dist, 0x3f, sizeof dist);int hh = 0, tt = 0;q[0] = 1;dist[1]  = 0;st[1] = true;while(hh <= tt){auto t = q[ hh ++];st[t] = false;for(int i = h[t]; ~i; i = ne[i]){int j = e[i];if(dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];                                                              if(!st[j]){q[ ++ tt] = j;st[j] = true;}}}}if(dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

第二类:多源汇最短路(Floyd)

源点:起点;汇点:终点;
假定边为m,顶点为n
任选两个点,从其中一个点到另外一个点的最短距离。即起点和终点不确定。很多不同起点到其他点的最短路
算法 :Floyd 算法, 时间复杂度O(n3)O(n^3)O(n3)

考察侧重点:建图。

可以用有向图的算法直接解决无向图的问题。

最短路[Dijkstra和堆优化的Dijkstra][Bellman-Ford和SPFA][Floyd最短路](更新中)相关推荐

  1. AcWing 850. Dijkstra求最短路 II【最短路】【堆优化版Dijkstra】

    AcWing 850. Dijkstra求最短路 II 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 AcWing 850. Dijkstra求 ...

  2. 堆优化版dijkstra算法:AcWing 850. Dijkstra求最短路 II

    堆优化版dijkstra算法分析: 朴素版dijkstra的时间复杂度为O(n^2),主要瓶颈在于第1步的寻找全局最小值的过程. 可以用小根堆(C++STL priority_queue)对dist数 ...

  3. c++ 堆优化版dijkstra 代码实现

    dijkstra是图论中解决最短路问题的重要算法之一,必须熟练掌握 dijkstra用于解决单源最短路问题,要求图中必须不存在负边权 朴素dijkstra的时间复杂度为O(n^2),堆优化版dijks ...

  4. PAT甲级1003 Emergency Dijkstra算法(堆优化版/朴素版)

    前言   最近花了很多的时间在写JAVA项目上面,疏忽了算法和数据结构的学习.最近突然醒悟基础更为重要,打算从今天开始每天抽出一些时间做下PAT甲级的题目.现有题库的前两题很简单,从第三题开始吧. 题 ...

  5. bzoj 3040: 最短路(road)(堆优化dijkstra)

    3040: 最短路(road) Time Limit: 60 Sec  Memory Limit: 200 MB Submit: 2811  Solved: 933 [Submit][Status][ ...

  6. 牛客 刺客信条 (bfs、dijkstra)+堆优化、dfs三种求解

    最短路 BFS+优先队列 DFS dijkstra+堆优化 题目描述 万物皆虚,万事皆允,玩过刺客信条的人对这句话应该都不会感到陌生 小A也是非常痴迷于这款游戏,正巧最近<刺客信条·奥德赛> ...

  7. SPFA or bellman ford松弛法--单源最短路

    问题概述:有编号1-n的n个站点,有m条公交车路线,公交车只从一个起点站直接到达终点站,是单向的且每条路线有它自己的车费,有P个人早上从1出发,他们要到达每一个公交站点,然后到了晚上再返回点1,求所有 ...

  8. ~~堆优化版dijkstra

    时间复杂度 O(mlogn), n 表示点数,m 表示边数 typedef pair<int, int> PII;int n; // 点的数量 int h[N], w[N], e[N], ...

  9. PAT甲级1131 Subway Map (30分):[C++题解]堆优化dijkstra、单源最短路、地铁地图、巧妙地建图套dijkstra模板!!

    文章目录 题目分析 题目链接 题目分析 原题: 来源:acwing 分析: 建图:所有能走到的点之间建立一条边,比如下面一条地铁线路有4站,它们是相通的,两两之间建一条边,边权是经过的站点数. 下面考 ...

最新文章

  1. 简单的BMCP位图图片压缩算法
  2. C/Cpp / 类的前向声明、不完全类型和完全类型
  3. Mysql数值型字符串按照数值进行排序
  4. WebRTC通话质量调优:三个弱网模拟测试工具的使用与对比
  5. 超像素分割算法matlab_像素不够,算法来凑。这个图像超分辨率项目帮你「拍」出高清照片...
  6. word删除分页符_5个Word删除空白页的方法,简单又高效,总有一个能帮你轻松秒杀...
  7. [转]数据安全之SQL注入资料整理
  8. redis技术分享ppt_精美PPT制作培训 | 技术二部内部分享
  9. python 服务端渲染_详解React 服务端渲染方案完美的解决方案
  10. mac地址厂商查询_3.15干货你的手机mac地址泄漏了吗
  11. 使用CSS和javascript制作拼图验证码
  12. android GitLab使用教程
  13. 基于flask的可视化动漫分析网站
  14. 微信小程序之使用云存储
  15. 制作纯净的U盘启动盘(避免纯净系统安装后却内置垃圾软件)
  16. OpenCV路在何方
  17. 一文理解所有需求分析中的基本术语
  18. 《漫步华尔街》 读书笔记 part1 历史
  19. python切换前端的iframe页面_如何切换到iframe窗口?
  20. Galera:多主同步MySQL集群原理解析

热门文章

  1. Sqoop找不到主类 Error: Could not find or load main class org.apache.sqoop.Sqoop
  2. java(13)内部类
  3. HttpContext.Current.Cache 过期时间
  4. Dynamic Web Module 3.0 requires Java 1.6 or newer
  5. Android动画之Tween动画实战
  6. php框架设计(图)
  7. 面向接口编程详解(三)——模式研究
  8. 某公司的一道机考题的解答
  9. linux多节点部署,Linux下docker部署+面板portainer管理多节点docker
  10. lisp点转为vla_一种将Region转为Polyline的方法