【模板】SPFA(不完全详解)
一种最短路求法(个人觉得比DIJKSTRA好用)
用于有向图。
大概思路:从根节点开始,枚举每一个点,同时更新他们所联通的点的最短路径,如果路径被更新,则把这个点入队,一直重复这个操作直到队伍为空为止。
代码:
struct edge {
int next, to, v;
}e[];//存图,next代表同一个头结点的下一条边
void spfa(int S) {
int p, x, y, l, r;
for (x = ; x <= n; ++x)
dis[x] = inf;
q[] = S, dis[S] = , v[S] = ;//初始化
for (l = r = ; l != (r + ) % N; ) {
p = q[l], ++l %= N;//每次取出队首
for (x = first[p]; x; x = e[x].next)//遍历与队首同头的每一条边
if (dis[p] + e[x].v < dis[(y = e[x].to)]) {//如果可以更新
dis[y] = dis[p] + e[x].v;//更新
if (!v[y]) {
v[y] = ;
q[++r %= N] = y;//入队
}
}
v[p] = ;
}
}
但是这种做法容易被卡掉(神奇奶牛),所以可以采用SLF优化。
SLF优化:每一次都把即将入队的值与队首值比较,若比队首值小,则存入队首。
为什么呢?
因为每一次都会从队首开始遍历,当队首是最小值时,被更新的所以节点的值也会是最小值,这样可以节省很大一部分时间。
(有点抽象。。举个例子吧)
(我不想画图)



这里需要注意:只有dis[]存储路径值,q[]存储的是当前最小路径值所在的位置,包括edge里的next也是同一个起点的上一对点的序号。(这里的头就是First[]的下标)
这里各种各样的序号很多。。特别容易弄混。会把各种序号分段输出的程序放在结尾,看不懂的话试几组样例看看输出会很有帮助。
到这里只是第一次更新。
下面是第二次更新:

接下来就可以以此类推了。。如果看不懂的话下面是分段输出的代码,结合上面的图看,体会一下中心思想。
代码:
#include<iostream>
using namespace std;
struct edge {
int next, to, v;
edge(){}
edge(int x,int y,int z)
{
next=x;
to=y;
v=z;
}
}e[]; int first[];
int tot;
int dis[];
int q[];
int v[];
void add_edge(int x, int y,int z) {
e[++tot] = edge(first[x], y,z);
first[x] = tot;
}
int n;
int N=; int inc(int x) {
x = x + ;
x = x % N;
return x;
} int dec(int x) {
x = x - + N;
x = x % N;
return x;
} void spfa(int S) {
int p, x, y, l, r;
for (x = ; x <= n; ++x)
dis[x] = 0x7ffff;
q[] = S, dis[S] = , v[S] = ;
for (l = r = ; l != (r + ) % N; ) {
p = q[l];
cout<<"从第"<<p<<"号边开始遍历"<<endl;
l=inc(l);
for (x = first[p]; x; x = e[x].next)
{
cout<<"这时是第"<<x<<"号边"<<endl;
if (dis[p] + e[x].v < dis[(y = e[x].to)]) {
cout<<"更新"<<" "<<"将"<<dis[y];
dis[y] = dis[p] + e[x].v;
cout<<"更新为"<<dis[y]<<endl;
if (!v[y]) {
v[y] = ;
if (dis[y] < dis[q[l]])
{q[(l=dec(l))] = y;
cout<<"从队首插入"<<y<<endl;
cout<<"这时l为"<<l<<"r不变"<<endl;
}
else
{q[(r=inc(r))] = y;
cout<<"从队尾插入"<<y<<endl;
cout<<"这时l不变r变为"<<r<<endl; }
cout<<"更新后的队列为"<<endl;
for(int i=;i<=n;i++)
{
cout<<q[i]<<" ";
} cout<<endl;
cout<<"入队情况为"<<endl;
for(int i=;i<=n;i++)
cout<<"第"<<i<<"号元素"<<v[i]<<" ";
cout<<endl;
}
}
}
v[p] = ;
cout<<"此时最短路径被更新为"<<endl;
for(int i=;i<=n;i++)
{
cout<<dis[i]<<" ";
}
cout<<endl;
}
} int main()
{
int m,S;
cin>>n>>m>>S;
int x,y,z;
for(int i=;i<=m;i++)
{
cin>>x>>y>>z;
add_edge(x,y,z);
} spfa(S);
cout<<"最终最短路径"<<endl;
for(int i=;i<=n;i++)
{
cout<<dis[i]<<" ";
} cout<<"一共有"<<tot<<"个节点,分别是"<<endl;
for(int i=;i<=tot;i++)
{
cout<<"与它同起点的上一对点为"<<e[i].next<<"号"<<" "<<"它指向"<<e[i].to<<"这个点"<<endl;
}
cout<<"下面输出First数组"<<endl;
for(int i=;i<=tot;i++)
{
cout<<first[i]<<" ";
} }
这是举例用的样例:
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
到这里就结束啦!希望可以看懂!
蒟蒻的第二篇博客(再放个烟花吧!)
【模板】SPFA(不完全详解)的更多相关文章
- 高性能JavaScript模板引擎实现原理详解
这篇文章主要介绍了JavaScript模板引擎实现原理详解,本文着重讲解artTemplate模板的实现原理,它采用预编译方式让性能有了质的飞跃,是其它知名模板引擎的25.32 倍,需要的朋友可以参考 ...
- OpenCV模板匹配函数matchTemplate详解
参考文档:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matchin ...
- Javascript模板引擎mustache.js详解
mustache.js是一个简单强大的Javascript模板引擎,使用它可以简化在js代码中的html编写,压缩后只有9KB,非常值得在项目中使用.本文总结它的使用方法和一些使用心得,内容不算很高深 ...
- *ecshop 模板中foreach用法详解
1.foreach分以下几个参数 from, item, name, iteration, index 2.使用foreach循环 如果php要传递一个数组(如:$array)给ecshop ...
- ThinkPHP模板IF标签用法详解
投稿:shichen2014 字体:[增加 减小] 类型:转载 时间:2014-07-01 我要评论 这篇文章主要介绍了ThinkPHP模板IF标签用法,需要的朋友可以参考下 ThinkPHP的IF标 ...
- Python时间获取详解,Django获取时间详解,模板中获取时间详解(navie时间和aware时间)
1.Python获取到的时间 import pytz from datetime import datetime now = datetime.now() # 这个时间为navie时间(自己不知道自己 ...
- Ecshop模板中html_options用法详解
程序部分 <?php $smarty->assign('status_list', $_LANG['cs']); // 订单状态 $smarty->display("ind ...
- 【Python-Django】Jinja2模板引擎配置教程详解!!!!
Jinjia2的官方文档:http://jinja.pocoo.org/docs/2.10/ 1. 安装Jinja2扩展包 $ pip install Jinja2 2. 配置Jinja2模板引擎 T ...
- Bellman-ford算法与SPFA算法思想详解及判负权环(负权回路)
我们先看一下负权环为什么这么特殊:在一个图中,只要一个多边结构不是负权环,那么重复经过此结构时就会导致代价不断增大.在多边结构中唯有负权环会导致重复经过时代价不断减小,故在一些最短路径算法中可能会凭借 ...
- 帝国CMS模板$GLOBALS[navclassid]用法详解
帝国CMS模板程序扩展变量说明:通过这些变量可实现各种更复杂的显示格式. 一.列表/封面模板变量说明:(栏目页或专题页中使用) (一).当前栏目ID或专题ID:$GLOBALS[navclassid] ...
随机推荐
- Codevs 1851 越狱 2008年湖南省队选拔赛
1851 越狱 2008年湖南省队选拔赛 时间限制: 10 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 监狱有连续编号为1-N的N个房间,每 ...
- SpringMVC——入门
一.SpringMVC介绍: Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请 ...
- 使用matplotlib绘制常用图表(1)
#导入相关包from matplotlib import pyplot as plt import matplotlib from matplotlib import font_manager #初始 ...
- Android_(控件)使用ListView显示Android系统中联系人信息
使用ListView显示手机中联系人的姓名和电话号码 父类布局activity_main.xml,子类布局line.xml(一个文件的单独存放) 运行截图: (避免泄露信息对部分地方进行了涂鸦O(∩_ ...
- Bzoj3073Journeys
这不裸的dij吗?来,弄他. 打完以后发现不妙,这数据范围略神奇……算一算,考一场都可能跑不出来.map去重边(成功额外引入log)不怕,交.TLE,54. 这不玩呢吗,把map去了,交.MLE,71 ...
- [eclipse]如何修改Eclipse编辑器的字体
步骤如下, 菜单->"Window"->“Preference”->“General”->“Appearance”->“Colors & Fo ...
- 最少步数&P1443 马的遍历
1330:[例8.3]最少步数 s数组:记录(1,1)到达每一点需要的最少步数 s[1][1]自然为 0,其余初始化为 -1 que数组:que[#][1] 表示(1,1)可到达点的 x 坐标 q ...
- LC 966. Vowel Spellchecker
Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word ...
- 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略
身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...
- WPF使用cefsharp 下载地址
源码下载: https://github.com/cefsharp/CefSharp dll类库包下载nuget: https://www.nuget.org/packages/CefSharp.Wp ...