签到题……

题目传送门

SPFA算法

本人曾经写过一篇有关Bellman-ford的博,但就算是挂了优化的ford也只能过这道题的弱化版。

今天就先填个坑,先讲SPFA。

在这里我直接认为你们已经有一定图论基础,至少知道啥是松弛之类的……

什么?你不知道?请移步百度……

spfa算法的一般时间复杂度:\(O(KM)\),M为边数,K为每个节点平均进队次数,经测试接近4,所以spfa一般情况下是很高效的。

spfa算法的最坏时间复杂度:\(O(NM)\),spfa算法可以被恶意卡到与bellman-ford一样的效率。

spfa被认为在随机的稀疏图中表现出色。

SPFA伪代码:

queue<int>q;//这个队列可是spfa的重点所在!
int n,m,s;//n是点数,m是边数,s是源点
struct node{
int to,val;//用来邻接表存图的结构体,to是目标点,val是边权值
};
int dis[10001];//distance数组不用说
bool vis[10001];//vis数组的作用是标记是否在队列中
vector<node>gragh[10001];//邻接表存图
inline void spfa(){
for(int i=1;i<=n;i++){
if(i==s)continue;
dis[i]=0x3f3f3f3f;
}
//这个初始化,不用说。
int t;//t是当前到哪个点了
q.push(s);//q队列最开始push进s去
vis[s]=1;//给s点一个标记
while(!q.empty()){//spfa终止的标志是队列为空
t=q.front();q.pop();//我们取出队头的这个元素,赋给t
for(int i=0;i<gragh[t].size();i++){//遍历所有与t相连的点
if(dis[t]+gragh[t][i].val<dis[gragh[t][i].to]){//如果满足松弛条件
//注意这里,我们是满足松弛条件才进行松弛,而不是直接一个min解决,这是因为松弛后紧跟的是入队操作,也是spfa进行常数优化的重点
dis[gragh[t][i].to]=dis[t]+gragh[t][i].val;//松弛操作
if(!vis[gragh[t][i].to]){//判断,若被松弛的点没入队
q.push(gragh[t][i].to);//直接入队
vis[gragh[t][i].to]=1;//打上标记
}
}
}
vis[t]=0;//别忘了我们在开头把t点pop出来了,要把标记消掉。
}
}

本人的马蜂清奇,可能有人看不懂这个邻接表啥意思,实际很简单啊,我来贴一下输入代码就明白了

for(int i=1;i<=m;i++){
scanf("%d %d %d",&u,&v,&w);//依次输入入点,出点,边权值
gragh[u].push_back({v,w});//在入点那个vector里push一下destination和value。
}

我们来讲一下spfa是怎么对bellman-ford优化的:

首先,明确一点,一个点什么时候必须需要松弛操作?当且仅当与它相连的点发生了松弛时!

q队列中存放的时是进行了松弛后所影响到的有待松弛的点

vis数组是给正在队列中的元素打标记的,防止元素重复进入队列。

这几句明白了,spfa基本就明白了。

spfa的基本思路:

  1. 初始化,将起点扔进队列,打上标记
  2. 把队头元素取出,并遍历与之相连的节点,如果能进行松弛则前往步骤3,不能跳过
  3. 对该节点进行松弛,如果该节点在队列中,跳过,不在队列中进行步骤4
  4. 将该节点扔进队列。
  5. 遍历结束后,消除原队头元素的标记(就是我们在步骤2中拿出来的那个),然后重复步骤2直到队列为空。

    到这里,spfa就讲完了,蒟蒻自认为讲的很清楚……

dijkstra算法

原始算法

dijkstra算法是巧妙运用贪心求图上单源最短路径的算法,时间复杂度为\(O(n^2)\)

dijkstra只适用于边权为正的图,如果为负,则贪心性质遭到破坏。

伪代码:

int n,m,s;
bool vis[maxn];
int dis[amxn];
int now=s;
memset(dis,0x3f,sizeof(dis));
dis[sourse]=0;
struct node{
int to,val;
}
vector<node>gragh[maxn];
//算法主体开始
while(!vis[now]){
for(int i=0;i<gragh[now].size();i++){
dis[gragh[now][i].to]=min(dis[gragh[now][i].to],dis[now]+gragh[now][i].val);
}//对当前节点进行松弛操作
vis[now]=1;//给当前节点打标记
int minn=0x3f3f3f3f;
for(int i=1;i<=n;i++){//遍历所有点,在没有被打标记的点中找到dis最小的点,更新为now
if(vis[i]==0&&ans[i]<minn){
minn=ans[i];
now=i;
}
}
}

算法基本思路:

  1. 初始化,同其他算法基本一致
  2. 对当前点进行松弛,标记。
  3. 在没有被打标记的点中找到dis最小的点,更新当前点
  4. 重复2,直到所有点都被标记

    思路大致就是这么个思路,但是,裸的dijkstra还是不行,我们为了追求更快的速度,看到了这里:
for(int i=1;i<=n;i++){//遍历所有点,在没有被打标记的点中找到dis最小的点,更新为now
if(vis[i]==0&&ans[i]<minn){
minn=ans[i];
now=i;
}
}

既然是动态维护序列最小值,我们想到了优先队列

堆优化

伪代码:

#define maxn 100001
#define maxm 200001
#define inf 0x3f3f3f3f
int n,m,s,u,v,w;
struct node{
int to,val;
};
bool vis[maxn];
vector<node>gragh[maxn];
int dis[maxn];
struct point{
int id,distance;
bool operator < (const point & a)const{//重载<,适用于结构体
return distance>a.distance;
}
};
priority_queue<point>q;
void dijkstra(){
for(int i=1;i<=n;i++){
if(i==s)continue;
dis[i]=inf;
}//初始化
q.push({s,0});//把起点扔进堆
while(!q.empty()){
point curr=q.top();q.pop();//取出队头
if(vis[curr.id])continue;//注意!这一句不能少,有可能堆中出现id相同但是distance不同的情况
vis[curr.id]=1;//vis数组在这里的意思是这个点进没进过堆。
for(int i=0;i<gragh[curr.id].size();i++){//遍历与之相连的所有点
if(dis[gragh[curr.id][i].to]>dis[curr.id]+gragh[curr.id][i].val){//若能松弛
dis[gragh[curr.id][i].to]=dis[curr.id]+gragh[curr.id][i].val;//松弛
q.push({gragh[curr.id][i].to,dis[gragh[curr.id][i].to]});//把被松弛的点扔进堆,格式{点的序号,当前distance}
}
}
}
}

这样优化,dijkstra就被优化到了这个复杂度:\(O(m log m)\)

对于大多数题这个复杂度稳过了。

算法之Dijkstra及其堆优化和SPFA:图上单源最短路径神器的更多相关文章

  1. 在 Prim 算法中使用 pb_ds 堆优化

    在 Prim 算法中使用 pb_ds 堆优化 Prim 算法用于求最小生成树(Minimum Spanning Tree,简称 MST),其本质是一种贪心的加点法.对于一个各点相互连通的无向图而言,P ...

  2. POJ-2387.Til the Cows Come Home.(五种方法:Dijkstra + Dijkstra堆优化 + Bellman-Ford + SPFA + Floyd-Warshall)

    昨天刚学习完最短路的算法,今天开始练题发现我是真的菜呀,居然能忘记邻接表是怎么写的,真的是菜的真实...... 为了弥补自己的菜,我决定这道题我就要用五种办法写出,并在Dijkstra算法堆优化中另外 ...

  3. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  4. Dijkstra和堆优化

    Dijkstra算法 由于我之前一直记的迪杰斯特拉的翻译导致我把dijkstra写成了dijstra--所以下文#define dijstra dijkstra 我以后叫她迪杰克斯歘! Dijskra ...

  5. 洛谷 P4779 【dijkstra】+(堆优化)+(链式前向星) (模板题)

    <题目链接> 题目描述 给定一个 N 个点, M 条有向边的带非负权图,请你计算从 S 出发,到每个点的距离. 数据保证你能从 S 出发到任意点. 输入格式: 第一行为三个正整数 N,M, ...

  6. Dijkstra+优先队列 堆优化

    关于堆优化 传统\(Dijkstra\),在选取中转站时,是遍历取当前最小距离节点,但是我们其实可以利用小根堆(STL的priority_queue)优化这个过程,从而大大降低复杂(\(O(V2+E) ...

  7. Dijkstra的堆优化

    先附上一个例题:P3371 [模板]单源最短路径 一眼扫去,最短路... spfa可行,但是今天的主题是Dijkstra: #include<iostream> #include<a ...

  8. POJ 3013 Big Christmas Tree(最短Dijkstra+优先级队列优化,SPFA)

    POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA) ACM 题目地址:POJ 3013 题意:  圣诞树是由n个节点和e个边构成的,点编号1-n. ...

  9. Dijkstra及其堆优化

    朴素Dijkstra #include<bits/stdc++.h> using namespace std; const int inf=9999999; bool book[105]; ...

  10. POJ 3635 - Full Tank? - [最短路变形][手写二叉堆优化Dijkstra][配对堆优化Dijkstra]

    题目链接:http://poj.org/problem?id=3635 题意题解等均参考:POJ 3635 - Full Tank? - [最短路变形][优先队列优化Dijkstra]. 一些口胡: ...

随机推荐

  1. 什么是齐博/齐博CMS之X1?

    齐博x1:核心+模块+插件+钩子的理念把系统的灵活性及拓展性做到了极致!!!齐博X1是齐博软件基于thinkphp5开发的内容管理系统,拓展性非常强,后台一键升级,后台提供丰富的频道模块云市插件市场. ...

  2. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  3. C#实现生成Markdown文档目录树

    前言 之前我写了一篇关于C#处理Markdown文档的文章:C#解析Markdown文档,实现替换图片链接操作 算是第一次尝试使用C#处理Markdown文档,然后最近又把博客网站的前台改了一下,目前 ...

  4. Nginx反向代理实现Tomcat+Jpress和halo

    一.利用Nginx反向代理Jpress+Tomcat 1.环境准备 服务器 IP地址 作用 系统版本 Proxy代理服务器 10.0.0.101 负载均衡Nginx Web服务器 Ubuntu2004 ...

  5. Archlinux安装Picgo配置Typora

    Typora堪称为markdown界的老大哥,其大名我们多有耳闻,所见即所的就是他的特点.但是在日常使用中,也经常会碰到一些特别的需求,比如:希望图片能够上传到云端. 怎么将markdown即时粘贴的 ...

  6. 32bit和64bit系统的区别,运行机制浅析

    32bit:内存的最大寻址空间是2^32=4G,就是说32位系统的处理器最大只支持到4G内存 64bit:内存的最大寻址空间是2^64,大于1亿GB,但是实际上支持不到那么大的内存,大概是2^40+ ...

  7. SpringBoot 08: SpringBoot综合使用 MyBatis, Dubbo, Redis

    业务背景 Student表 CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) COL ...

  8. PGL图学习之图神经网络GNN模型GCN、GAT[系列六]

    PGL图学习之图神经网络GNN模型GCN.GAT[系列六] 项目链接:一键fork直接跑程序 https://aistudio.baidu.com/aistudio/projectdetail/505 ...

  9. NET 6 实现滑动验证码(一)、创建工程

    目录 实现滑动验证码的目的 创建.NET 6工程 实现滑动验证码的目的 传统验证码实现起来比较简单,但在OCR技术越来越成熟的情况下,验证码的破解难度越来越低,但如果将验证码难度加高(各种干扰背景,扭 ...

  10. Encodings: URL

    原题链接:http://www.wechall.net/challenge/training/encodings/url/index.php 题目信息:你的任务就是解码下面的东西.... 这个完全没难 ...