dijkstra算法学习笔记
dijkstra是一种单源最短路径算法,即求一个点到其他点的最短路。不能处理负边权。
最近某种广为人知的算法频繁被卡,让dijkstra逐渐成为了主流,甚至在初赛中鞭尸了SPFA(?
dijkstra效率还是不错的,而且不容易被卡。
一、主要思想
用dis数组保存最短路径。初始化时,dis[s]设置为0(s为起点),其他无穷大。
枚举点i,每次从i能够到达的点中,选出权值最小的一个mpl(min place 个人叫法),把dis[mpl]直接设置为权值。可以证明,这就是最短的路径。
证明:若不是,则必有点k,能使
s->k+k->mpl < s->mpl
由权值最小得 s->mpl < s->k 明显矛盾
(我居然没写易证!
再枚举mpl到达的点k,若mpl->k+dis[mpl] > dis[k] 则更新dis[k]。专业术语叫做:松弛。
以此类推,更新完所有的点,算法结束。复杂度O(n2)
代码:
#include<iostream>
#include<vector>
#include<cstring> using namespace std; //GDT TQL Orz struct edge {
int next,to,dis;
} g[];//前向星 int dis[],gdt[],n,m,s,u,v,w,ne=;
//gdt就是head数组。此处为玩梗QwQ inline void add(int from,int to,int d) {
g[++ne].next=gdt[from];
g[ne].to=to;
g[ne].dis=d;
gdt[from]=ne;
}//前向星建边 inline void dijkstra() {
int mn,mpl=s;
bool vis[]= {};
dis[s]=;
for(register int i=;i<=n;i++)
{
mn=;
for(register int now=; now<=n; now++) {
if(dis[now]<mn&&!vis[now]) {
mn=dis[now];
mpl=now;
}
}
//选出权值最小的点
vis[mpl]=;
//此节点已被拓展,也就是变为白点(你们可能会从奇奇怪怪
//的算法书中得到这种说法)。
for(register int now=gdt[mpl]; now; now=g[now].next) {
if(!vis[g[now].to]&&dis[g[now].to]>dis[mpl]+g[now].dis)
dis[g[now].to]=dis[mpl]+g[now].dis;
} }
} int main() {
memset(gdt,,sizeof(gdt));
memset(g,,sizeof(g));
cin>>n>>m>>s;
for(int i=; i<=n; i++)
dis[i]=; for(int i=; i<=m; i++) {
cin>>u>>v>>w;
add(u,v,w);
}
dijkstra();
for(int i=; i<=n; i++) {
cout<<dis[i]<<' ';
}
return ;
}
二、堆优化
所谓堆,实际相当于一个优先队列。
每次把点入队,使用时直接可以访问离s距离最小的。
具体实现时,会用STL中的priority_queue(优先队列)。而且,一个点需要一个地址(访问)和一个距离s的最短距离(比较、更新最短路径)。
代码:
#include<iostream>
#include<vector>
#include<cstring>
#include<queue> using namespace std; //GDT TQL Orz struct edge
{
int next,to,dis;
}g[]; struct node
{
int k,v;
//地址key,权值value
}; bool operator < (node n1,node n2)
{
return n1.v>n2.v;
} //优先队列维护时需要比较,而结构体无法直接比较,使用重载运算符。 int dis[],gdt[],n,m,s,u,v,w,ne=; inline void add(int from,int to,int d)
{
g[++ne].next=gdt[from];
g[ne].to=to;
g[ne].dis=d;
gdt[from]=ne;
} inline void dijkstra()
{
int mn,mpl=s;
node nd,temp;
bool vis[]= {};
dis[s]=;
priority_queue<node> pq;
temp.k=s;
temp.v=;
pq.push(temp);//第一个点更新起点
while(!pq.empty())
{
nd=pq.top();
pq.pop(); if(vis[nd.k]) continue;
vis[nd.k]=;//拓展
mpl=nd.k;
for(register int now=gdt[mpl]; now; now=g[now].next)
{
if(!vis[g[now].to]&&dis[g[now].to]>dis[mpl]+g[now].dis)
{
dis[g[now].to]=dis[mpl]+g[now].dis;
temp.k=g[now].to;
temp.v=dis[g[now].to];
pq.push(temp);//新的一个结点
}
}
}
} int main() {
memset(gdt,,sizeof(gdt));
memset(g,,sizeof(g));
cin>>n>>m>>s;
for(int i=; i<=n; i++)
dis[i]=; for(int i=; i<=m; i++)
{
cin>>u>>v>>w;
add(u,v,w);
}
dijkstra();
for(int i=; i<=n; i++)
{
cout<<dis[i]<<' ';
}
return ;
}
三、关于SPFA
如果一个图没有负边权,那就一定会卡你的SPFA。
dijkstra算法学习笔记的更多相关文章
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- dijkstra算法学习
dijkstra算法学习 一.最短路径 单源最短路径:计算源点到其他各顶点的最短路径的长度 全局最短路径:图中任意两点的最短路径 Dijkstra.Bellman-Ford.SPFA求单源最短路径 F ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- 算法学习笔记(三) 最短路 Dijkstra 和 Floyd 算法
图论中一个经典问题就是求最短路.最为基础和最为经典的算法莫过于 Dijkstra 和 Floyd 算法,一个是贪心算法,一个是动态规划.这也是算法中的两大经典代表.用一个简单图在纸上一步一步演算,也是 ...
- SPFA算法学习笔记
一.理论准备 为了学习网络流,先水一道spfa. SPFA算法是1994年西南交通大学段凡丁提出,只要最短路径存在,SPFA算法必定能求出最小值,SPFA对Bellman-Ford算法优化的关键之处在 ...
- 算法学习笔记——sort 和 qsort 提供的快速排序
这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...
随机推荐
- Android零基础入门第77节:Activity任务栈和启动模式
通过前面的学习,Activity的基本使用都已掌握,接下来一起来学习更高级的一些内容. Android采用任务栈(Task)的方式来管理Activity的实例.当启动一个应用时,Android就会为之 ...
- 最小二乘法 good
最小二乘法也称为最小平方法,是一种数据优化技术,它通过最小化误差的平方和寻找数据的最佳函数匹配. 最小二乘法最初由高尔顿在创立回归分析的时候提出,现在已经成为探索变量间关系最重要的方法,最小二乘法根据 ...
- 2015元旦第一弹——WP8.1应用程序栏(C#后台代码编写)
//第一次写博文,以后还请各位道友互相关照哈.废话不多说,直接进入正题. 相信大家对于如何在XAML添加应用程序栏应该很清楚,不清楚的话,可以打开新建个Pviot应用 就有系统自带的菜单栏. 本文主要 ...
- 在Visual Studio2015中使用单元测试
所谓的单元测试(Unit Test),就是对软件的一些模块进行测试以检查其正确性和可靠性,这些模块可以是一个类或者是一个方法等.在Visual studio中,这十分容易实现. 打开Visual st ...
- 微软Skype实时口译增加中文
直击现场 在机器翻译技术上,微软的 Skype 业务也算是行业内名列前茅.日前其实时口语翻译技术再次跃升一个台阶,新增了对中文(普通话)的翻译支持. 据美国科技新闻网站 TheVerge 报道,此前, ...
- Linux 桌面玩家指南:19. 深入理解 JavaScript,及其开发调试工具
特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...
- c#实现类似数据的行锁
当我们有一些这样的需求,比如某个订单中下单,修改等等这些是单例执行的,不能同步操作,当然这样的情况你可以使用数据库的行锁来实现,但是我们代码里面实现的话 ,我们也要用到锁,大部分情况下我们使用lock ...
- 学习Java,容易被你忽略的小细节(2)
昨天心情真的太糟糕了,写完<学习Java,值得注意你注意的问题(1)>之后,迎来些许的支持以后就是一片片的谴责.我的主页上涌现出许许多多Java方面的牛人,谴责我水平太低,写的问题太初级. ...
- 30255Java_5.5 GUI
GUI GUI的各种元素(如:窗口,按钮,文本框等)由Java类来实现 1.AWT 使用AWT所涉及的类一般在java.awt包及其子包中 AWT(Abstract Window Toolkit)包括 ...
- sso和oauth2.0的简单了解学习
sso,单点登录,single sign on 缩写.sso多用于多个应用之间的切换,例如百度论坛.百度知道.百度云.百度文库等,在其中一个系统中登录,(登录有效期内)切换到另一个系统的时候,不必再次 ...