最短路[Dijkstra和堆优化的Dijkstra][Bellman-Ford和SPFA][Floyd最短路](更新中)
文章目录
- 第一类:单源最短路
- 一 所有边权都是正数(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为限定的边数)。
算法思路:
- 扫描所有边(x, y, z),这里指的是从x到y,边权为z的边 ,如果dist[y] > dist[x] + z, 则用dist[x] + z 更新dist[y].
- 重复上述步骤,直到没有更新操作发生。
而spfa算法呢,在国际上通常称为”队列优化的Bellman-Ford算法“。它是对Bellman-Ford算法的优化,一般而言,我们刷题用的多的还是spfa。
SPFA算法 一般情况下比Bellman-Ford快,时间复杂度O(m)O(m)O(m),最坏O(nm)O(nm)O(nm),适合于负权边
spfa算法流程:
- 建立一个队列,最初队列中只含有起点1
- 取出队头结点x,扫描它的所有出边(x, y, z),如果dist[y] > dist[x] + z, 则用dist[x] + z 更新dist[y].同时, 若y不在队列中,则把y入队。
- 重复上述步骤,直到队列为空。
851. spfa求最短路
来源:acwing
- spfa代码和堆优化dijkstra很像。只不过spfa用的是队列
queue
。关于queue的操作,取出队头元素是front()
;存入元素是push()
.当然建图同样是邻接表。 - 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最短路](更新中)相关推荐
- AcWing 850. Dijkstra求最短路 II【最短路】【堆优化版Dijkstra】
AcWing 850. Dijkstra求最短路 II 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 AcWing 850. Dijkstra求 ...
- 堆优化版dijkstra算法:AcWing 850. Dijkstra求最短路 II
堆优化版dijkstra算法分析: 朴素版dijkstra的时间复杂度为O(n^2),主要瓶颈在于第1步的寻找全局最小值的过程. 可以用小根堆(C++STL priority_queue)对dist数 ...
- c++ 堆优化版dijkstra 代码实现
dijkstra是图论中解决最短路问题的重要算法之一,必须熟练掌握 dijkstra用于解决单源最短路问题,要求图中必须不存在负边权 朴素dijkstra的时间复杂度为O(n^2),堆优化版dijks ...
- PAT甲级1003 Emergency Dijkstra算法(堆优化版/朴素版)
前言 最近花了很多的时间在写JAVA项目上面,疏忽了算法和数据结构的学习.最近突然醒悟基础更为重要,打算从今天开始每天抽出一些时间做下PAT甲级的题目.现有题库的前两题很简单,从第三题开始吧. 题 ...
- bzoj 3040: 最短路(road)(堆优化dijkstra)
3040: 最短路(road) Time Limit: 60 Sec Memory Limit: 200 MB Submit: 2811 Solved: 933 [Submit][Status][ ...
- 牛客 刺客信条 (bfs、dijkstra)+堆优化、dfs三种求解
最短路 BFS+优先队列 DFS dijkstra+堆优化 题目描述 万物皆虚,万事皆允,玩过刺客信条的人对这句话应该都不会感到陌生 小A也是非常痴迷于这款游戏,正巧最近<刺客信条·奥德赛> ...
- SPFA or bellman ford松弛法--单源最短路
问题概述:有编号1-n的n个站点,有m条公交车路线,公交车只从一个起点站直接到达终点站,是单向的且每条路线有它自己的车费,有P个人早上从1出发,他们要到达每一个公交站点,然后到了晚上再返回点1,求所有 ...
- ~~堆优化版dijkstra
时间复杂度 O(mlogn), n 表示点数,m 表示边数 typedef pair<int, int> PII;int n; // 点的数量 int h[N], w[N], e[N], ...
- PAT甲级1131 Subway Map (30分):[C++题解]堆优化dijkstra、单源最短路、地铁地图、巧妙地建图套dijkstra模板!!
文章目录 题目分析 题目链接 题目分析 原题: 来源:acwing 分析: 建图:所有能走到的点之间建立一条边,比如下面一条地铁线路有4站,它们是相通的,两两之间建一条边,边权是经过的站点数. 下面考 ...
最新文章
- 简单的BMCP位图图片压缩算法
- C/Cpp / 类的前向声明、不完全类型和完全类型
- Mysql数值型字符串按照数值进行排序
- WebRTC通话质量调优:三个弱网模拟测试工具的使用与对比
- 超像素分割算法matlab_像素不够,算法来凑。这个图像超分辨率项目帮你「拍」出高清照片...
- word删除分页符_5个Word删除空白页的方法,简单又高效,总有一个能帮你轻松秒杀...
- [转]数据安全之SQL注入资料整理
- redis技术分享ppt_精美PPT制作培训 | 技术二部内部分享
- python 服务端渲染_详解React 服务端渲染方案完美的解决方案
- mac地址厂商查询_3.15干货你的手机mac地址泄漏了吗
- 使用CSS和javascript制作拼图验证码
- android GitLab使用教程
- 基于flask的可视化动漫分析网站
- 微信小程序之使用云存储
- 制作纯净的U盘启动盘(避免纯净系统安装后却内置垃圾软件)
- OpenCV路在何方
- 一文理解所有需求分析中的基本术语
- 《漫步华尔街》 读书笔记 part1 历史
- python切换前端的iframe页面_如何切换到iframe窗口?
- Galera:多主同步MySQL集群原理解析
热门文章
- Sqoop找不到主类 Error: Could not find or load main class org.apache.sqoop.Sqoop
- java(13)内部类
- HttpContext.Current.Cache 过期时间
- Dynamic Web Module 3.0 requires Java 1.6 or newer
- Android动画之Tween动画实战
- php框架设计(图)
- 面向接口编程详解(三)——模式研究
- 某公司的一道机考题的解答
- linux多节点部署,Linux下docker部署+面板portainer管理多节点docker
- lisp点转为vla_一种将Region转为Polyline的方法