dijkstra其实是bfs?--重新定义dijkstra
- 1前言
- 2最短路径问题
- 3没有边权的最短路--bfs算法
- 4边权的加入
- 5优先队列与dijkstra
- 6后记
1前言
本文将介绍dijkstra算法全新的理解方式
建议新手对dijkstra有建议了解,强烈推荐这篇文章,无比详细
2最短路径问题
最短路径问题,顾名思义,就是在图上找一条从起点到终点的最短路径
最短路径问题也有不同的分类
我们今天将研究的,是解决单源最短路最常用的算法–dijkstra
3没有边权的最短路–bfs算法
有些最短路问题,所有边都没有边权,可以视为边权为
1
1
1
这也是最短路最简单的问题,甚至可以称为图的遍历的模板
那么,广度优先搜索bfs算法的原理是什么呢?
将图分层(如图)
(bfs分层图的思想在网络流问题中也有体现,建议阅读)
每个点的层次用蓝色标注
很容易得
1
−
7
1-7
1−7的最短路径长度为
4
4
4
但是,点
5
5
5也可以由
4
4
4到达,为什么不把它划分到第四层呢
这就要说到bfs中的队列了
众所周知,队列是一种FIFO(first in first out,先进先出)的数据结构
每搜到一个点,就先入队,
2
2
2显然比
4
4
4先入队,就要先出队,来更新
5
5
5点
我们关注队列里的元素,它们对应的层次单调不减
我们存储一下入队的顺序,就是图的bfs序
也就是说,优先选取层次小的点来更新,这就是bfs
4边权的加入
我们为这些边增加权值
如下图(边权用蓝色标出)
我们再用bfs跑一遍,
2
2
2点先更新
5
5
5点
标记
1
1
1点到
5
5
5点的最短路径为
5
5
5
但是此时,我们先走
4
4
4,你就会发现,路径长度仅为
4
4
4,更短了
我们的bfs就这样在带权图里被hack了…
5优先队列与dijkstra
看到这里,想必你也知道了,此时bfs队列里的值不再具有单调性
那怎么办?
还记得优先队列(堆)吗,可以动态维护队列内的最值(堆的原理便不再赘述)
我们把队列换成优先队列不就好了吗
这就是dijkstra,一个优先队列优化的bfs
所有人都告诉你dijkstra用堆是来优化的
可是我认为,有堆的dijkstra才是真正的dijkstra
但是,怎么确定有没有更小的值还没入队呢
这里就要说到dijkstra的精髓了
首先,所有在未来可能入堆的值都由现在的值直接或间接得到
路不可能越走越短,所以在堆的外面没用更小值
但是,我们还要存一下起点到每个点的最短路径,因为可能出现一个点更新多次的情况
这下再用堆,算法就成了…吗?
如果有边的边权是负数呢
显然用不了dijkstra,这就要用spfa
但是一般情况边权是正的,要用dijkstra!会卡spfa!
附代码(c++)
#include<bits/stdc++.h>
using namespace std;
const int Max=1e5+100;
struct node{
int nxt,v,w;
}a[Max*2];
struct lis{
int val,id;
};
bool operator<(const lis &u,const lis &v){
return u.val>v.val;
}
bool vis[Max];
int head[Max*2],cnt;
int dis[Max];
void add(int u,int v,int w){
a[++cnt]={head[u],v,w};
head[u]=cnt;
}
void dijkstra(int s,int n){
priority_queue<lis>q;
memset(dis,63,sizeof(dis));
vis[s]=0;
dis[s]=0;
q.push({0,s});
while(!q.empty()){
int k=q.top().id;
q.pop();
if(vis[k])continue;
vis[k]=1;
for(int i=head[k];i!=0;i=a[i].nxt){
int v=a[i].v,w=a[i].w;
if(dis[v]>dis[k]+w){
dis[v]=dis[k]+w;
q.push({dis[v],v});
}
}
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m;
cin >> n >> m;
for(int i=0;i<m;i++){
int x,y,z;
cin >> x >> y >> z;
add(x,y,z);
}
dijkstra(1,n);
cout << dis[n];
return 0;
}
6后记
作者把dijkstra看成bfs的行为可能存在问题,如有错误请各位神犇指点
关注CSDN@森林古猿1,看更多c++教学
森林古猿出品,必属精品,请认准CSDN@森林古猿1
关注CSDN@一个很不专业的编程小白,c++算法超详解