A simple dispiction of dijkstra
前言
- \(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的更多相关文章
- tricks - 思维
编辑 目录 tricks 系列 随机的性质 bitmask 建图 最基本的 黑白染色 Kruskal重构树 并查集维护值域 带根号的数三元环 根号分治 调和级数哈希 多属性哈希 时光倒流 时光反复横跳 ...
- [ACM_图论] Domino Effect (POJ1135 Dijkstra算法 SSSP 单源最短路算法 中等 模板)
Description Did you know that you can use domino bones for other things besides playing Dominoes? Ta ...
- POJ 1135 Domino Effect (Dijkstra 最短路)
Domino Effect Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9335 Accepted: 2325 Des ...
- 一个对 Dijkstra 的采访视频
之前在微博上推荐了一个对 Dijkstra 的采访视频,看了两遍之后觉得实在很好,所以再正式推荐一下.大部分人可能都知道他对图论算法和操作系统的贡献,而其实 Dijkstra 在程序语言上的造诣也很深 ...
- 【转】一个对 Dijkstra 的采访视频
一个对 Dijkstra 的采访视频 (也可以访问 YouTube 或者从源地址下载 MPEG1,300M) 之前在微博上推荐了一个对 Dijkstra 的采访视频,看了两遍之后觉得实在很好,所以再正 ...
- 数据结构与算法-图的最短路径Dijkstra
一 无向图单源最短路径,Dijkstra算法 计算源点a到图中其他节点的最短距离,是一种贪心算法.利用局部最优,求解全局最优解. 设立一个visited访问和dist距离数组,在初始化后每一次收集一 ...
- BNU 4356 ——A Simple But Difficult Problem——————【快速幂、模运算】
A Simple But Difficult Problem Time Limit: 5000ms Memory Limit: 65536KB 64-bit integer IO format: %l ...
- BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】
A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...
- HDU 6166.Senior Pan()-最短路(Dijkstra添加超源点、超汇点)+二进制划分集合 (2017 Multi-University Training Contest - Team 9 1006)
学长好久之前讲的,本来好久好久之前就要写题解的,一直都没写,懒死_(:з」∠)_ Senior Pan Time Limit: 12000/6000 MS (Java/Others) Memor ...
随机推荐
- Tr/ee AtCoder - 4433 (构造)
大意: 给定长$n$的字符串$s$, 要求构造一棵树, 满足若第$i$个字符为$1$, 那么可以删一条边, 得到一个大小为$i$的连通块. 若为$0$则表示不存在一条边删去后得到大小为$i$的连通块. ...
- Kafka 系列(一)—— Kafka 简介
一.简介 ApacheKafka 是一个分布式的流处理平台.它具有以下特点: 支持消息的发布和订阅,类似于 RabbtMQ.ActiveMQ 等消息队列: 支持数据实时处理: 能保证消息的可靠性投递: ...
- linux 压力测试工具之ab
简介 Apache Benchmark(简称ab) 是Apache安装包中自带的压力测试工具 ,简单易用 在此提供 ab 在 centOS7 下的安装和使用方法注:个人发现,之前安装的centos6. ...
- 记录screen屏幕日志
1.建立日志存放目录#mkdir /var/log/screen/ 2.修改配置文件,在末尾添加配置内容#vi /etc/screenrclogfile /var/log/screen/%t.log ...
- 如何使用Git 优雅的版本回退呢?
在版本迭代开发过程中,相信很多人都会有过错误提交的时候(至少良许有过几次这样的体验).这种情况下,菜鸟程序员可能就会虎驱一震,紧张得不知所措.而资深程序员就会微微一笑,摸一摸锃亮的脑门,然后默默的进行 ...
- celery 定时任务,使用crontab表达式不执行(版本4.3.x)
celery 定时任务,使用crontab表达式不执行(版本4.3.x) 在使用celery 执行定时任务时,发现任务不会执行,schedule设置如下: 经测试,如果去掉hour,则任务每分钟都会执 ...
- css3 media媒体查询器用法总结(附js兼容方法)
css3 media媒体查询器用法总结 标签:class 代码 style html sp src 随着响应式设计模型的诞生,Web网站又要发生翻天腹地的改革浪潮,可能有些人会觉得 ...
- vue 利用v-model实现父子组件数据双向绑定
v-model父组件写法: v-model子组件写法: 子组件export default中的model:{}里面两个值,prop代表着我要和props的那个变量相对应,event表示着事件,我触发事 ...
- react学习记录(一)
一.React是什么 声明式写法(强调结果,命令式编程强调过程) 组件化 一次学习,随处编写(多种应用场景,web程序,原生手机应用,系统应用,命令行工具) 二.为什么学习react 大公司加持-fa ...
- Upgrade Windows Server 2016 to Windows Server 2019
Pre-Upgrade Upgrade path: Windows Server 2016 can be upgraded to Windows 2019 in a single upgrade pr ...