文章目录

  • SPFA简介
  • 链式前向星介绍
  • SPFA算法思路详细
  • 模板-链式前向星

参考书籍:算法竞赛入门到进阶 罗勇军


SPFA简介

用队列处理Bellman-Ford算法可以很好地优化,这种方法叫做SPFA。SPFA的效率很高,在算法竞赛中的应用很广泛。

Bellman-Ford算法有很多低效或无效的操作。分析Bellman-Ford算法,其核心部分是在每一轮操作中更新所有结点到起点s的最短距离。根据前面的讨论可知,计算和调整一个结点u到s的最短距离后,如果紧接着调整u的邻居结点,这些邻居肯定有新的计算结果;而如果漫无目的地计算不与u相邻的结点,很可能毫无变化,所以这些操作是低效的。

因此,在计算结点u之后,下一步只计算和调整它的邻居,这样能加快收敛的过程。这些步骤可以用队列进行操作,这就是SPFA

SPFA很像BFS;

①起点s入队,计算它所有邻居到s的最短距离(当前最短距离,不是全局最短距离。在下文中,把计算一个结点到起点s的最短距离简称更新状态。最后的“状态”就是SPFA的计算结果)。把s出队,状态有更新的邻居入队,没更新的不入队。也就是说,队列中都是状态有变化的结点,只有这些结点才会影响最短路径的计算。

②现在队列的头部是s的一个邻居u。弹出u,更新其所有邻居的状态,把其中有状态变化的邻居入队列。

③这里有一个问题,弹出u之后,在后面的计算中u可能会再次更新状态(后来发现,u借道其他结点去s,路更近)。所以,u可能需要重新入队列。这一点很容易做到:在处理一个新的结点v时,它的邻居可能就是以前处理过的u,如果u的状态变化了,把u重新加入队列就行了。

④继续以上过程,直到队列空。这也意味着所有结点的状态都不再更新。最后的状态就是到起点s的最短路径。

上面的第(3)点决定了SPFA的效率。有可能只有很少结点重新进入队列,也有可能很多。这取决于图的特征,即使两个图的结点和边的数量一样,但是边的权值不同,它们的SPFA队列也可能差别很大。所以,SPFA是不稳定的。

在比赛时,有的题目可能故意卡SPFA的不稳定性:如果一个题目的规模很大,并且边的权值为非负数,它很可能故意设置了不利于SPFA的测试数据。此时不能冒险用SPFA,而是用Dijkstra算法。Dijkstra算法是一种稳定的算法,一次迭代至少能找到一个结点到s的最短路径,最多只需要m(边数)次迭代即可完成。

链式前向星介绍

(链式前向星的优点)

存储效率高、程序简单、能存储重边


以结点2为例,从点2出发的边有4条,即(2,1)(2,3)(2,4)(2,5),邻居是1、3、4、5 。

①定位第1个边。用head[ ]数组实现,例如head[ 2 ]指向结点2的第1个边,head[ 2 ] = 8 ,它存储在 edge[ 8 ] 这个位置。

②定位其他边。用struct edge 的next参数指向下一个边。edge[ 8 ] .next = 6,指向下一边在edge[ 6 ]这个位置,然后edge[ 6 ].next = 4,edge[ 4 ].next = 1,最后edge[ 1 ].next = -1 , -1表示结束。

struct edge的to参数记录这个边的邻居结点。例如edge[ 8 ].to = 5,第一个邻居是点5;然后edge[ 6 ].to = 4,edge[ 4 ].to = 3,edge[1].to = 1,得到邻居是1、3、4、5。

由于链式前向星用静态数组来模拟邻接表,没有任何浪费,故是空间效率最高的存储方法。


SPFA算法思路详细

具体参考这篇博客:
SPFA算法实例分析 【图解+详细松弛操作】


模板-链式前向星

HDU 2544的SPFA算法代码(链式前向星)

#include<bits/stdc++.h>
#define endl '\n'
#define mst(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1000005;
const int INF=INT_MAX/10;
struct node{int to,ne,w;
}stu[maxn];
int n,m,cnt;
int head[maxn]; //头结点静态数组
int dis[maxn];  //记录所有节点到源点的距离
int Neg[maxn];  //判断负圈(Negative loop)
bool vis[maxn]; vis[i]=true表示结点i在队列中
void init(){  //初始化for(int i=0;i<maxn;i++){head[i]=-1;stu[i].ne=-1;}cnt=0;
}
void add(int u,int v,int w){  //前向星存图stu[cnt].to=v;stu[cnt].w=w;stu[cnt].ne=head[u];head[u]=cnt++;
}
int spfa(int s){memset(Neg,0,sizeof(Neg));Neg[s]=1;for(int i=1;i<=n;i++)dis[i]=INF,vis[i]=false;  //初始化dis[s]=0;                     //源点到自己的距离为0queue<int> Q;Q.push(s);vis[s]=true;                  //源点进队列while(!Q.empty()){int u=Q.front(); Q.pop();vis[u]=false;for(int i=head[u];~i;i=stu[i].ne){   //~i也可以写成i!=-1int v=stu[i].to;int w=stu[i].w;if(dis[v]>dis[u]+w){            //u的第i个邻居v,它借道u,到s更近dis[v]=dis[u]+w;            //更新第i个邻居到s的距离if(!vis[v]){                vis[v]=true;Q.push(v);Neg[v]++;if(Neg[v]>n) return 1; //出现负圈情况}}}}return 0;
}
int main(){ios::sync_with_stdio(false);cin.tie(0);while(cin>>n>>m&&(n+m)){init();while(m--){int u,v,w;cin>>u>>v>>w;add(u,v,w);add(v,u,w);}spfa(1);cout<<dis[n]<<endl;}return 0;
}
学如逆水行舟,不进则退

图论:SPFA 算法详解( 算法竞赛入门到进阶) HDU 2544 链式前向星 【提供ACM模板+图解,不会都难!】相关推荐

  1. 迪杰斯特拉最全详解(朴素版,堆优化+邻接表存图/链式前向星存图)

    迪杰斯特拉 迪杰斯特拉算法分析 迪杰斯特拉(朴素版) 迪杰斯特拉堆优化(邻接表存图) 迪杰斯特拉堆优化(链式前向星存图) 最短路--spfa(链式前向星存图) 迪杰斯特拉算法分析 一般用三种数据结构存 ...

  2. 前向星和链式前向星(详解+模板)

    前向星和链式前向星 参考博客:深度理解链式前向星 什么是前向星 前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,并记录下以某个点为起点的 ...

  3. spfa(链式前向星)+dijkstra(链式前向星)

    链式前向星 链式前向星可以存图, 它存图的方式是: 将任意一个节点的所有临边按输入顺序依次连接起来将任意一个节点的所有临边按输入顺序依次连接起来将任意一个节点的所有临边按输入顺序依次连接起来 然后头节 ...

  4. 图论部分模板(基于链式前向星的存储方式)

    图论篇部分模板(基于链式前向星的存储方式) 你还在为暴力枚举复杂度太高而苦恼吗?你还在为DP而痛苦吗?你还在为搜索剪枝而绞尽脑汁吗?选择链式前向星吧,链式前向星--专注存图20年 . 1. 链式前向星 ...

  5. Day 7 A - Age of Moyu HDU 6386 | 最短路 | SPFA | 链式前向星

    松弛:原来用一根橡皮筋连接p和w两点,现在有一点v到w的路径更短,现在把橡皮筋w点的另一端p换成v点,这样缓解橡皮筋紧绷的压力,让其变得松弛. 来自:原博 关于SPFA算法 来自:原博 链式前向星 # ...

  6. 【模板】链式前向星+spfa

    洛谷传送门--分糖果 博客--链式前向星 团队中一道题,数据很大,只能用链式前向星存储,spfa求单源最短路. 可做模板. #include <cstdio> #include <q ...

  7. 洛谷 P2756 飞行员配对方案问题 二分图 匈牙利算法 链式前向星 汉子找妹子模型 最大流模板 FF算法

    题目链接: https://www.luogu.com.cn/problem/P2756 方法一: 算法:1:匈牙利算法 思路:1:汉子找妹子模型 #include<bits/stdc++.h& ...

  8. 链式前向星存图(有图详解)

    链式前向星:既然是链式那么肯定和链表相关,前向星是每次指向都向前 链式前向星存图是以边为中心,并不是以结点为中心,它记录的是边的一些属性,包括边边的id.头节点.尾结点.权值.边的指向! 边的指向是遍 ...

  9. tarjan算法详解--图论--强连通图

    目录 1.有向图连通性(强连通图) 1.1有向图 1.2有向图连通性 2.tarjan算法简述 3.实现过程 3.1 例题-刻录光盘 3.1.1 输入&&初始化 3.1.2 tarja ...

最新文章

  1. Swift2.0语言教程之函数的返回值与函数类型
  2. 每句话都可以品味一生
  3. 高中生毕业落榜学计算机,高中毕业落榜了 不想复读怎么办_2019年高考落榜怎么办...
  4. Thymeleaf——访问静态资源(static)解决方案
  5. hadoop小型集群_小型Hadoop集群的Ganglia配置和一些故障排除
  6. 解决删除镜像时image is referenced in multiple repositories
  7. 指尖初体验之主屏幕操作
  8. 韩顺平php视频笔记68 析构函数 php垃圾回收机制
  9. zeroc ice的概念、组成与服务
  10. Python生成requirements.txt方法
  11. Atitti 模板匹配 Listjava.awt.Point matchTemplate(
  12. 域名抢注流程是什么?
  13. 电影《检察风云》投资价值简单分析
  14. mysql5.7.19winx64安装_winx64下mysql5.7.19的基本安装流程(详细)
  15. svn查找历史版本_svn历史版本对比以及还原到历史版本
  16. P2471 [SCOI2007]降雨量(线段树)
  17. 鸿蒙之境法有三乘,神都夜行录鸿蒙之境怎么打 神都夜行录鸿蒙之境阵容搭配推荐...
  18. oracle怎么查日记账,Oracle EBS 导入日记账报错
  19. playsound 模块解决 UnicodeDecodeError 异常
  20. js 跨域访问问题解决方法

热门文章

  1. spring实战学习(四)AOP及其实现方式
  2. Win10 系统安装
  3. 逻辑回归与线性回归算法梳理
  4. 回归算法-线性回归分析-正规方程和梯度下降
  5. IIS6.0文件解析缺陷(asa,cer,cdx)
  6. 那个业务大拿死在了这个地方
  7. 分析:人名搜索Spock会成下个谷歌吗
  8. python基础练习题(一)
  9. 计算机中毒症状简介,电脑中毒的八大表现,第五个大多数人都不知道!
  10. 基于matlab的光学薄膜特性分析,基于matlab的光学薄膜特性分析