dijkstra其实是bfs?--重新定义dijkstra

1前言

本文将介绍dijkstra算法全新的理解方式
建议新手对dijkstra有建议了解,强烈推荐这篇文章,无比详细

2最短路径问题

最短路径问题,顾名思义,就是在图上找一条从起点到终点的最短路径
最短路径问题也有不同的分类
我们今天将研究的,是解决单源最短路最常用的算法–dijkstra

3没有边权的最短路–bfs算法

有些最短路问题,所有边都没有边权,可以视为边权为 1 1 1
这也是最短路最简单的问题,甚至可以称为图的遍历的模板
那么,广度优先搜索bfs算法的原理是什么呢?
将图分层(如图)
(bfs分层图的思想在网络流问题中也有体现,建议阅读
在这里插入图片描述
每个点的层次用蓝色标注
很容易得 1 − 7 1-7 17的最短路径长度为 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++算法超详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值