SPFA算法(SLF优化)2022.7.8更新
SPFA可能会被卡掉,能用dijkstra就别用SPFA,代码较长,但我已尽力做到解释,请耐心看下去,存储为邻接表存储。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f//(宏定义一个很大的值,例如0x3f3f3f3f等)
using namespace std;
int n,m,cnt;//cnt 计数器(有cnt条边)
struct edge//结构体定义
{
int v,w,nxt;//v 目标点 w 边权 nxt 这条边的上一条边(遍历)
};
edge e[3000010];//存边(边表)
int dis[3001000];//记录起点到第x个点的距离
int h[1001000];//记录第x个点所发出的最后一条边
bool f[1001000];//判断是否在队列内
deque<int> q;//双端队列
void add(int,int,int);
void spfa()//SLF优化
{
for(int i=1;i<=n;++i)
{
dis[i]=inf;
}//初始化,也可以用memset()
dis[1]=0;//起点到自己的距离为0 (该题起点为1)
q.push_back(1);//起点入队
f[1]=1;//标志起点已入队
while(!q.empty())
{
int top=q.front();//取队首元素
q.pop_front();//踢出队列
int w=dis[top];//w 起点的值
f[top]=0;//代表该元素已出队
for(int i=h[top];i;i=e[i].nxt)//邻接表遍历每一条边
{
int v=e[i].v;//目标点
int di=e[i].w;//边权
if(dis[v]>w+di)//松弛操作
{
dis[v]=w+di;//更新起点到点v的值
if(!f[v])//判断是否入队,没入队便入队
{
if(!q.empty()&&dis[v]<dis[q.front()])//如果比队首元素小,从队首入队
{//这里一定要把!q.empty()放在前面,编译时它会从前往后读,如果把它放后面而队列又为空,dis[v]<dis[q.front()]调用时会RE
q.push_front(v);//入队操作
}
else q.push_back(v);//否则从队尾入队
f[v]=1;//标志已入队
}
}
}
}
}
int main()
{
memset(h,0,sizeof h);//数组初始化
memset(f,false,sizeof f);//数组初始化
scanf("%d%d",&n,&m);
for(int a,b,c,i=1;i<=m;++i)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c); //加边
add(b,a,c);//加边,如果是有向图,删掉这一步操作
}
spfa();//调用函数
printf("%d",dis[n]);//输出,根据题目要求,这里是输出1到n的最短距离
return 0;
}
void add(int u,int v,int w)
{
e[++cnt].v=v;//cnt 边的编号
e[cnt].w=w;
e[cnt].nxt=h[u];//指向上一条边
h[u]=cnt;//更新最后一条边
}
2022.7.8更新:
新增判断负环的写法和dfs写法
dfs写法判断负环更快,但求答案很慢
bfs队列写法求答案快,但判断负环很慢
根据题目情况来
bfs队列写法:
bool spfa()
{
for(rint i=1;i<=n;++i)
dis[i]=0x7ffffff;
dis[0]=0;
q.push_back(0);
vis[0]=true;
++in[0];//差记录入队次数
while(!q.empty())
{
int u=q.front();
q.pop_front();
vis[u]=false;
for(rint i=h[u];i;i=e[i].nxt)
{
int v=e[i].v;ll w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(!vis[v])
{
++in[v];
if(in[v]>=n+1) return false;//判断负环
if(!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v);
else q.push_back(v);
vis[v]=true;
}
}
}
}
return true;
}
dfs写法:
void dfs_spfa(int u)
{
if(fg) return;
vis[u]=true;
for(rint i=h[u];i;i=e[i].nxt)
{
int v=e[i].v;
ll w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(vis[v]==true)//如果这个点被访问过,就说明这是负环
{
fg=true;//打标记
return;
}
else dfs_spfa(v);
}
}
vis[u]=false;
}
SPFA算法(SLF优化)2022.7.8更新的更多相关文章
- 关于SPFA算法的优化方式
关于SPFA算法的优化方式 这篇随笔讲解信息学奥林匹克竞赛中图论部分的求最短路算法SPFA的两种优化方式.学习这两种优化算法需要有SPFA朴素算法的学习经验.在本随笔中SPFA朴素算法的相关知识将不予 ...
- spfa的SLF优化
spfa的SLF优化就是small label first 优化,当加入一个新点v的时候如果此时的dis[v]比队首dis[q.front()]还要小的话,就把v点加入到队首,否则把他加入到队尾,因为 ...
- HDU4725(KB4-P SPFA+LLL+SLF优化)
The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- 并不对劲的图论专题(三):SPFA算法的优化
1.bzoj1489-> 这是个新套路. 我们希望找到最小的x,那么可以二分x,然后判断是否存在圈的边权的平均值小于等于x. 设圈的边权依次为w1,w2,w3,…,wk,平均值为p, 则有p= ...
- 《SPFA算法的优化及应用》——姜碧野(学习笔记)
一.核心性质:三角不等式.最短路满足d[v]<=d[u]+w(u,v) 二.SPFA两种实现: 常见的是基于bfs的,这是直接对bellman-ford用队列维护.根据最短路的长度最长为(n-1 ...
- 蓝书3.3 SPFA算法的优化
T1 最小圈 bzoj 1486 题目大意: 一个环的权值平均值为定义为一个这个环上所有边的权值和除以边数 求最小的环的权值平均值 思路: 二分一个值 把所有边减去这个值 判断是否有负环 #inclu ...
- 队列优化dijsktra(SPFA)的玄学优化
转载:大佬博客 最近想到了许多优化spfa的方法,这里想写个日报与大家探讨下 前置知识:spfa(不带任何优化) 由于使用较多 STLSTL ,本文中所有代码的评测均开启 O_2O2 优化 对一些数 ...
- SPFA算法的SLF优化 ——loj#10081. 「一本通 3.2 练习 7」道路和航线
今天做到一道最短路的题,原题https://loj.ac/problem/10081 题目大意为给一张有n个顶点的图,点与点之间有m1条道路,m2条航线,道路是双向的,且权值非负,而航线是单向的,权值 ...
- SPFA求最短路——Bellman-Ford算法的优化
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环.SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE), ...
随机推荐
- 推荐一款数据mock框架,无需任何依赖,贼牛逼
fox-mock 是基于Java Agent实现的自测,联调Mock利器.能解决你的这些问题: 开发过程中,依赖了下游多个接口,想跑个单测都必须得等下游把服务部署好 联调过程中,下游某个接口出问题,阻 ...
- 关闭BottomSheetDialogFragment从后台返回后的动画
问题 显示BottomSheetDialogFragment后.将当前应用放于后台,切换到其他APP,然后再返回当前应用.此时会看到BottomSheetDialogFragment从下而上的动画再次 ...
- 玩转ASP.NET 6.0框架-序言
ASP.NET Core是微软提供的强大的web框架,它有很多潜在的强大而有用的功能. 本专栏的目标是帮助您把框架的隐藏能力最大限度地发挥出来,让您能够按需定制ASP NET Core框架.本专栏提供 ...
- 每天一个 HTTP 状态码 101
101 Switching Protocols 当客户端的请求具有 Upgrade HTTP 首部,表示要求服务器切换到指定协议:此时服务器端就可以向客户端响应 101 Switching Proto ...
- 关于我学git这档子事(4)
------------恢复内容开始------------ 当本地分支(main/dev)比远程仓库分支(main/dev)落后几次提交时 先: git pull 更新本地仓库 再 git push ...
- 【题解】Codeforces Round #798 (Div. 2)
本篇为 Codeforces Round #798 (Div. 2) 也就是 CF1689 的题解,因本人水平比较菜,所以只有前四题 A.Lex String 题目描述 原题面 给定两个字符串 \(a ...
- Leetcode 1051. 高度检查器
这题的目的是找出排序后和排序前位置不同的元素的个数 正常通过复制出一个新的数组,然后对比排序后的数组就能做出,但是时间是1ms 然后发现一种基于桶排序来计数的做法 public int heightC ...
- SAP Web Dynpro - 应用程序中的服务调用
您可以使用服务调用来调用Web Dynpro组件中的现有功能模块. 要创建服务呼叫,您可以使用Web Dynpro工具中易于使用的向导. 您可以在ABAP工作台中启动该向导以创建服务调用. 步骤1-选 ...
- DAST 黑盒漏洞扫描器 第五篇:漏洞扫描引擎与服务能力
0X01 前言 转载请标明来源:https://www.cnblogs.com/huim/ 本身需要对外有良好的服务能力,对内流程透明,有日志.问题排查简便. 这里的服务能力指的是系统层面的服务,将扫 ...
- 深入理解 happens-before 原则
在前面的文章中,我们深入了解了 Java 内存模型,知道了 Java 内存模型诞生的意义,以及其要解决的问题.最终我们知道:Java 内存模型就是定义了 8 个基本操作以及 8 个规则,只要遵守这些规 ...