SPFA 全面讲解
SPFA全面讲解
——最短路高效算法
标签: 最短路
简介:SPFA 是1994年在西安交通大学段凡丁同学所提出,是将Dijsktra以及Bellman-Ford两种最短路算法完美结合的一个算法,效率十分的高。全名为Shortest Path Faster Algorithm,简称SPFA。
首先,在下面的讲解中,我们要用到几个变量:
- n 表示一共有n个点。
- s 表示开始点。
- t 表示结束点。
- dist[MAXN]:d[i]表示从s到i的最短路径
- head[MAXN]:head[i]记录前驱。
- queue\(<int>\)q,也就是队列。
- flag[MAXN]:f[i]表示i在不在队列中
\(SPFA可以处理负权边!!\)
首先add一个邻接表以及一个用来搞邻接表的struct
struct point
{
int from;
int to;
int next;
int len;
}edge[MAXN];
int total=0;
void add(int f,int t,int l)
{
edge[total++].from=f;
edge[total].to=t;
edge[total].next=head[f];
edge[total].len=l;
head[f]=total;
}
首先,我们先处理初始化,顺带输入。。。
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&s,&t);
for(int i=1;i<=n;i++)
dist[i]=INF;
//预处理操作
{
dist[s]=0;//源点到源点的距离为0
q.push(s);//将源点入队
flag[s]=1;//表示s点已经在队列中
}
SPFA(s);
}
然后就是队列+松弛操作。
int SPFA()
{
while(!q.empty())
{
int cnt=q.front();
q.pop();
flag[cnt]=0;
for(int i=head[cnt];i;i=edge[i].next)
if(dist[edge[i].to]>dist[cnt]*edge[i].len)
{
dist[edge[i].to]=dist[cnt]*edge[i].len;
if(!flag[edge[i].to])
{
flag[flag[edge[i].to]]=1;
q.push(edge[i].to);
}
}
}
}
那么正式的讲解从现在开始!!
首先我们建一个图用来方便讲解。
Title:现在我们建图, 里面包含有a b c d e f g
a->b: 24
a->d:15
a->c:8
c->f:3
c->e:7
f->e:2
b->e:6
e->g:9
g->b:3
f->g:3
f->d:5
看不看得懂呢?~ ~ ~
然后我们假设a为s。
那么我们现在建立一个从起始点a到个点的最短路径表格。
a->a:0
a->b:∞
a->c:∞
a->d:∞
a->e:∞
a->f:∞
a->g:∞
然后按照我们的SPFA的顺序,首先a入队,然后判断到队列非空。
将队首元素a出队.
然后对以a点为起始点的所有边进行松弛操作(此处只有e点。)。
此时表格的状态为:
a->a:0
a->b:24
a->c:8
a->d:15
a->e:∞
a->f:∞
a->g:∞
在松弛的时候三个点的最短路径(估值)变小了,然后检测到这些点在队列中还都没有出现。于是入队,此时队列中有了三个点:b,c,d。
然后队首元素c出队.
对以c为起始点的所有边进行松弛操作。
此时表格的状态变为:
a->a:0
a->b:24
a->c:8
a->d:15
a->e:30
a->f:∞
a->g:∞
此时在列表中e的路径估值也变小了,而且e不在队列之中,于是e也入队,于是队列中的元素变成了c,d,e。
然后队首元素c再次出队.
对所有以c为起始点的边进行松弛操作。
此时表格又变了样子:
a->a:0
a->b:24
a->c:8
a->d:15
a->e:15
a->f:11
a->g:∞
看到了e和f的最短路径估值再次变小,但是e在队列中但是f不在,于是将f入队。
队首元素d出队
对以d为起始点的所有边进行松弛操作。
表格再次变化:
a->a:0
a->b:24
a->c:8
a->d:15
a->e:15
a->f:11
a->g:19
此时g的最短路径估值没有变小,于是松弛失败,没有新节点入队。于是接着取队首,f,g......
最后我们的表格变成了这个样子:
a->a:0
a->b:17
a->c:8
a->d:15
a->e:13
a->f:11
a->g:14
此时e的最短路径估值没有变化,于是松弛失败,此时队列为空,于是程序结束。
然后我们要求的dist[g]就是14。
\(_完美收工_\) \(_完美收工_\) \(_完美收工_\) \(_完美收工_\) \(_完美收工_\) \(_完美收工_\) \(_完美收工_\)
那么下面给大家出一道SPFA的模板题,(用来存代码(#滑稽)
若要看具体题面请看链接:传送门
##题目描述:最短路
给定n个带权的有向图,,求1到n的最短的简单路径之积。
输入:
一共m+1行。
第一行:两个数n,m.分别表示点的总数以及边的总数。
第2到第m+1行:每一行三个数:分别为两个点以及连接这两个点的边权。
输出:
一行,共一个数:表示所求路径的边权之积mod 9987的值。
输入样例:
3 3
1 2 3
2 3 3
1 3 10
输出样例:
9
很明显的模板题了。下面是代码:
//Yeasion_nein
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#define MAXN 10010
using namespace std;
int n,m,head[1000010];
int dist[1000010];
bool flag[1000010];
queue<int>q;
int total;
struct e
{
int next;
int to;
int from;
int len;
}edge[1000010];
void add(int f,int t,int l)
{
edge[total++].from=f;
edge[total].to=t;
edge[total].next=head[f];
edge[total].len=l;
head[f]=total;
}
int SPFA()
{
while(!q.empty())
{
int cnt=q.front();
q.pop();
flag[cnt]=0;
for(int i=head[cnt];i;i=edge[i].next)
{
if(dist[edge[i].to]>dist[cnt]*edge[i].len)
{
dist[edge[i].to]=dist[cnt]*edge[i].len;
if(!flag[edge[i].to])
{
flag[flag[edge[i].to]]=1;
q.push(edge[i].to);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
dist[i]=0x7ffffff;
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d",&x);
scanf("%d",&y);
scanf("%d",&z);
add(x,y,z);
}
dist[1]=1;
q.push(1);
flag[1]=1;
SPFA();
printf("%d",dist[n]%9987);
return 0;
}
如果这篇博客有帮助到你的话,清点一下赞吧!!(qwq)
SPFA 全面讲解的更多相关文章
- spfa模板+讲解
zz http://blog.sina.com.cn/s/blog_6ad20aef0100mc1a.html Spfa算法 (模板源代码) 这是Bellman Ford的改进算法. 算法介绍: ...
- 图论最短路径算法——Dijkstra
说实在的,这算法很简单,很简单,很简单--因为它是贪心的,而且码量也小,常数比起SPFA也小. 主要思想 先初始化,dis[起点]=0,其它皆为无限大. 还要有一个bz数组,bz[i]表示i是否确定为 ...
- 【算法】祭奠spfa 最短路算法dijspfa
题目链接 本题解来源 其他链接 卡spfa的数据组 题解堆优化的dijkstra 题解spfa讲解 来自以上题解的图片来自常暗踏阴 使用前向星链表存图 直接用队列优化spfa struct cmp { ...
- 觉得一篇讲SPFA还不错的文章
我觉得他整理的有一些乱,我都改成插入代码了,看的顺眼一些 转载自http://blog.csdn.net/juststeps/article/details/8772755 下面的都是原文: 最短路径 ...
- 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)
这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...
- POJ3169--Layout(SPFA+差分系统)
Description Like everyone else, cows like to stand close to their friends when queuing for feed. FJ ...
- 关于$NOIP2017$的题目讲解
关于\(NOIP2017\)的题目讲解 1.小凯的疑惑 题目描述: 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法 ...
- 【最短路径】 SPFA算法
上一期介绍到了SPFA算法,只是一笔带过,这一期让我们详细的介绍一下SPFA. 1 SPFA原理介绍 SPFA算法和dijkstra算法特别像,总感觉自己讲的不行,同学说我的博客很辣鸡,推荐一个视频讲 ...
- 算法提高 道路和航路 SPFA 算法
我简单的描述一下题目,题目中所说的有道路和航路: 1.公路是双向的,航路是单向的: 2.公路是正值,航路可正可负: 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1 ...
随机推荐
- windows环境下MySQL-5.7.12-winx64下载安装与配置
系统:64位Win-7 官网压缩包:mysql-5.7.12-winx64.zip 前后花了一些时间,以前都是下载软件直接安装在本地,现在这个不一样,下载压缩包后要解压缩到安装目录,然后在控制台下配置 ...
- word 摘要
word 使用心得 定义快捷键 Tools -> Customize keyboard 自定义快捷键 cmd + L, 左对齐; cmd + R, 右对齐; cmd + E, 居中对齐 cmd ...
- Linux文本处理工具
Linux文本处理工具 Linux中熟练的使用文本处理工具非常的重要, 因为Linux在设计的时候是采用一切皆文件的哲学的, 甚至连计算机中的配置也都使用伪文件系统来表示, 要查询里面的内容就是对文件 ...
- nyoj 409——郁闷的C小加(三)——————【中缀式化前缀后缀并求值】
郁闷的C小加(三) 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考“郁闷的C小加(一)”),C小加很 ...
- jquery中Ajax提交配合PHP使用的注意事项-编码
问题:Ajax提交的数据的编码为utf-8,并且返回的数据也要求是utf-8的,如果说你的系统不是utf-8编码的话,那会让你痛不欲生! 解决方法:(比较笨拙的方法,但是很好用) 对于接收的数据,使用 ...
- 项目视图 Project Browser
项目视图 在这个视图,你可以访问.管理你当前项目资源. 项目视图左侧面板显示项目的文件夹结构的分层列表,当从列表中单击一个文件夹,其内容会显示在面板的右边.你可以点击小三角展开或折叠文件夹,显示他包含 ...
- Hibernate中的一对一注解配置
Card类 package cn.OneToOne2017109.entity; import javax.persistence.*; /** * Created by YSS on 2017/10 ...
- Cocos2d-js 开发记录:图片数据资源等的异步加载
这里说的是在需要的使用加载图片,比如游戏中的某个关卡的图片,不用在游戏一开始就加载(万一用户玩不到那关,岂不是很冤,流量费了那么多),否则载入速度也慢.这种方式加载资源要用到cc.loader官方文档 ...
- springboot--数据库操作
1.注意: 使用get,post提交时,使用form-data; 使用put提交方式,使用x-www-form-url-encoded,这是http的一种格式;
- foreach的基本语法
有一个布尔型循环是专门用来循环数组的.这个循环的基本语法就是foreach基本语法 foreach( 要循环的数组变量 as [键变量 =>] 值变量){ //循环的内容 } 这是一个固定用法, ...