前言

  • \(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. Ambari调整日志级别:How to enable debug logging in Ambari Server and Ambari Agent ?

    PURPOSE When troubleshooting Ambari issues, it may be necessary to enable debug logging in the Ambar ...

  2. idea之将Maven的jar包安装到本地仓库

    1.问题概要 很多时候,我们需要应用第三方的jar包,但是这个jar包,在maven远程仓库里面没有, 比如我们要使用京东的sdk,但这个sdk在maven的远程仓库中没有,于是我们需要将这个jar包 ...

  3. Jenkins+Docker+Git+Harbor流水线打包

    Jenkins+Docker+Git+Harbor流水线打包 环境: CentOS Linux release 7.6.1810 (Core) 192.168.247.214 Jenkins+dock ...

  4. ELK Stack部署

    部署ELK Stack 官网:https://www.elastic.co 环境准备: ip hostname 服务 用户.组 192.168.20.3 node2003 kibana6.5,file ...

  5. Redis开发与运维学习笔记

    <Redis开发与运维>读书笔记   一.初始Redis 1.Redis特性与优点 速度快.redis所有数据都存放于内存:是用C语言实现,更加贴近硬件:使用了单线程架构,避免了多线程竞争 ...

  6. 存储型XSS靶场作业

    首先进入靶场:http://59.63.200.79:8082/index.php xss平台使用:xss8c 发现CMS版本号,搜索是否此版本号存在可利用漏洞: 找到存储型xss漏洞,在xss平台生 ...

  7. Android打包遇到的问题

    问题一 运行环境 引擎:Unity 4.3.4f1 安卓:Android 6 打包机的环境 出错堆栈 Unity version : 4.3.4f1 Caused by: java.lang.Unsa ...

  8. web页面死链测试方法

    一.概述 > 来自百度百科释义 死链:指服务器的地址已经改变了.无法找到当前地址位置,包括协议死链和内容死链两种形式.死链出现的原因有网站服务器设置错误:某文件夹名称修改,路径错误链接变成死链等 ...

  9. [转载]Fiddler界面详解

    转载地址:http://www.cnblogs.com/chengchengla1990/p/5681775.html Statistics 页签 完整页签如下图: Statistics 页签显示当前 ...

  10. 项目Alpha冲刺(团队)-测试篇

    格式描述 课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(团队)-代码规范.冲刺任务与计划 团队名称:为了交项目干杯 测试用例:测试用例文档.zip 作业目标:描述项目的测试 ...