前言

  • \(SPFA\)算法由于它上限 \(O(NM) = O(VE)\)的时间复杂度,被卡掉的几率很大.在算法竞赛中,我们需要一个更稳定的算法:\(dijkstra\).

什么是\(dijkstra\)?

  • \(dijkstra\)是一种单源最短路径算法,时间复杂度上限为\(O(n^2)\)(朴素),在实际应用中较为稳定\(;\)加上堆优化之后更是具有\(O((n+m)\log_{2}n)\)的时间复杂度,在稠密图中有不俗的表现.

\(dijkstra\)的原理/流程?

  • \(dijkstra\)本质上的思想是贪心,它只适用于不含负权边的图.
  • 我们把点分成两类,一类是已经确定最短路径的点,称为"白点",另一类是未确定最短路径的点,称为"蓝点"
  • \(dijkstra\)的流程如下\(:\)
  • \(1.\) 初始化\(dis[start] = 0,\)其余节点的\(dis\)值为无穷大.
  • \(2.\) 找一个\(dis\)值最小的蓝点\(x,\)把节点\(x\)变成白点.
  • \(3.\) 遍历\(x\)的所有出边\((x,y,z),\)若\(dis[y] > dis[x] + z,\)则令\(dis[y] = dis[x] + z\)
  • \(4.\) 重复\(2,3\)两步,直到所有点都成为白点\(.\)
  • 时间复杂度为\(O(n^2)\)

\(dijkstra\)为什么是正确的

  • 当所有边长都是非负数的时候,全局最小值不可能再被其他节点更新.所以在第\(2\)步中找出的蓝点\(x\)必然满足\(:dis[x]\)已经是起点到\(x\)的最短路径\(.\)我们不断选择全局最小值进行标记和拓展,最终可以得到起点到每个节点的最短路径的长度

图解

  • (令\(start = 1\))
  • 开始时我们把\(dis[start]\)初始化为\(0\),其余点初始化为\(inf\)

  • 第一轮循环找到\(dis\)值最小的点\(1\),将\(1\)变成白点,对所有与\(1\)相连的蓝点的\(dis\)值进行修改,使得\(dis[2]=2,dis[3]=4,dis[4]=7\)

  • 第二轮循环找到\(dis\)值最小的点\(2\),将\(2\)变成白点,对所有与\(2\)相连的蓝点的\(dis\)值进行修改,使得\(dis[3]=3,dis[5]=4\)

  • 第三轮循环找到\(dis\)值最小的点\(3\),将\(3\)变成白点,对所有与\(2\)相连的蓝点的\(dis\)值进行修改,使得\(dis[4]=4\)

  • 接下来两轮循环分别将\(4,5\)设为白点,算法结束,求出所有点的最短路径
  • 时间复杂度\(O(n^2)\)

为什么\(dijkstra\)不能处理有负权边的情况?

  • 我们来看下面这张图

  • \(2\)到\(3\)的边权为\(-4\),显然从\(1\)到\(3\)的最短路径为\(-2\) \((1->2->3).\)但在循环开始时程序会找到当前\(dis\)值最小的点\(3\),并标记它为白点.
  • 这时的\(dis[3]=1,\)然而\(1\)并不是起点到\(3\)的最短路径.因为\(3\)已经被标为白点,所以\(dis[3]\)不会再被修改了.我们在边权存在负数的情况下得到了错误的答案.

\(dijkstra\)的堆优化?

  • 观察\(dijkstra\)的流程,发现步骤\(2\)可以优化

  • 怎么优化呢?

  • 我会zkw线段树!我会斐波那契堆!

  • 我会堆!

  • 我们可以用堆对\(dis\)数组进行维护,用\(O(\log_{2}n)\)的时间取出堆顶元素并删除,用\(O(\log_{2}n)\)遍历每条边,总复杂度\(O((n+m)\log_{2}n)\)

  • 范例代码:

#include<bits/stdc++.h>

const int MaxN = 100010, MaxM = 500010;

struct edge
{
int to, dis, next;
}; edge e[MaxM];
int head[MaxN], dis[MaxN], cnt;
bool vis[MaxN];
int n, m, s; inline void add_edge( int u, int v, int d )
{
cnt++;
e[cnt].dis = d;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
} struct node
{
int dis;
int pos;
bool operator <( const node &x )const
{
return x.dis < dis;
}
}; std::priority_queue<node> q; inline void dijkstra()
{
dis[s] = 0;
q.push( ( node ){0, s} );
while( !q.empty() )
{
node tmp = q.top();
q.pop();
int x = tmp.pos, d = tmp.dis;
if( vis[x] )
continue;
vis[x] = 1;
for( int i = head[x]; i; i = e[i].next )
{
int y = e[i].to;
if( dis[y] > dis[x] + e[i].dis )
{
dis[y] = dis[x] + e[i].dis;
if( !vis[y] )
{
q.push( ( node ){dis[y], y} );
}
}
}
}
} int main()
{
scanf( "%d%d%d", &n, &m, &s );
for(int i = 1; i <= n; ++i)dis[i] = 0x7fffffff;
for( register int i = 0; i < m; ++i )
{
register int u, v, d;
scanf( "%d%d%d", &u, &v, &d );
add_edge( u, v, d );
}
dijkstra();
for( int i = 1; i <= n; i++ )
printf( "%d ", dis[i] );
return 0;
}

例题

  • 入门模板:P3371
  • 进阶模板:P4779
  • 其余例题请右转洛谷题库,搜索"最短路"

后记

  • 本文部分内容摘自李煜东《算法竞赛进阶指南》和《信息学竞赛一本通》
  • 友情提示:正权图请使用\(dijkstra\)算法,负权图请使用\(SPFA\)算法

A simple dispiction of dijkstra的更多相关文章

  1. tricks - 思维

    编辑 目录 tricks 系列 随机的性质 bitmask 建图 最基本的 黑白染色 Kruskal重构树 并查集维护值域 带根号的数三元环 根号分治 调和级数哈希 多属性哈希 时光倒流 时光反复横跳 ...

  2. [ACM_图论] Domino Effect (POJ1135 Dijkstra算法 SSSP 单源最短路算法 中等 模板)

    Description Did you know that you can use domino bones for other things besides playing Dominoes? Ta ...

  3. POJ 1135 Domino Effect (Dijkstra 最短路)

    Domino Effect Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9335   Accepted: 2325 Des ...

  4. 一个对 Dijkstra 的采访视频

    之前在微博上推荐了一个对 Dijkstra 的采访视频,看了两遍之后觉得实在很好,所以再正式推荐一下.大部分人可能都知道他对图论算法和操作系统的贡献,而其实 Dijkstra 在程序语言上的造诣也很深 ...

  5. 【转】一个对 Dijkstra 的采访视频

    一个对 Dijkstra 的采访视频 (也可以访问 YouTube 或者从源地址下载 MPEG1,300M) 之前在微博上推荐了一个对 Dijkstra 的采访视频,看了两遍之后觉得实在很好,所以再正 ...

  6. 数据结构与算法-图的最短路径Dijkstra

    一  无向图单源最短路径,Dijkstra算法 计算源点a到图中其他节点的最短距离,是一种贪心算法.利用局部最优,求解全局最优解. 设立一个visited访问和dist距离数组,在初始化后每一次收集一 ...

  7. BNU 4356 ——A Simple But Difficult Problem——————【快速幂、模运算】

    A Simple But Difficult Problem Time Limit: 5000ms Memory Limit: 65536KB 64-bit integer IO format: %l ...

  8. BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

    A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...

  9. HDU 6166.Senior Pan()-最短路(Dijkstra添加超源点、超汇点)+二进制划分集合 (2017 Multi-University Training Contest - Team 9 1006)

    学长好久之前讲的,本来好久好久之前就要写题解的,一直都没写,懒死_(:з」∠)_ Senior Pan Time Limit: 12000/6000 MS (Java/Others)    Memor ...

随机推荐

  1. mysql修改后启动my.cnf报错Starting MySQL... ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.localdomain.pid).

    mysql中文乱码解决 mysql修改my.cnf后启动报错Starting MySQL... ERROR! The server quit without updating PID file (/v ...

  2. Spring Boot Freemarker特别篇之contextPath【从零开始学Spring Boot

      需求缘起:有人在群里@我:请教群主大神一个问题,spring boot  + freemarker 怎么获取contextPath 头疼死我了,网上没一个靠谱的 .我就看看之前博客中的 [Spri ...

  3. Linux RedHat7.0_64位系统中安装Oracle_11g_R2

    步骤一: 当然是安装rhel7操作系统啦(废话),建议在安装过程中系统软件类型选择最后一项[Server with GUI].其他的默认一般即可. 步骤二:在初装完成的系统中无法像Windows那样直 ...

  4. 2019 UCloudjava面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.UCloud等公司offer,岗位是Java后端开发,因为发展原因最终选择去了UCloud,入职一年时间了,也 ...

  5. Java 之 NOSQL

    一.什么是 NOSQL NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库. 随着互联网web2.0网站的兴起,传统的关系数据 ...

  6. 基于 k8s-搭建 Kubernetes 的 web 管理界面

    查看我们的k8s环境是否正常: 使用kubectl get nodes 获取我们的节点的信息: 到此说明我们的kubernetes环境是正常的,接下来就可以实验了 第一步在master上传所需的软件包 ...

  7. shell EOF 用户自定义终止符

    #!/bin/bash ftp -n << EOF user guest 123456 binary cd /home/ prompt mget * close bye EOF 使用Tab ...

  8. 实战FFmpeg + OpenGLES--iOS平台上视频解码和播放

    一个星期的努力终于搞定了视频的播放,利用FFmpeg解码视频,将解码的数据通过OpenGLES渲染播放.搞清楚了自己想知道的和完成了自己的学习计划,有点小兴奋.明天就是“五一”,放假三天,更开心啦. ...

  9. 【OGG】OGG的单向复制配置-支持DDL(二)

    [OGG]OGG的单向复制配置-支持DDL(二) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的 ...

  10. java web添加spring jar 包

    maven依赖: <properties> <spring.version>5.1.7.RELEASE</spring.version> </properti ...