【模板】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] ...
随机推荐
- Luogu P4139 上帝与集合的正确用法
题目链接:Click here Solution: 这道题就考你会不会扩展欧拉定理,根据扩展欧拉定理可知 \[ a^b \equiv a^{(b\,mod\,\varphi(p))+\varphi(p ...
- fflush函数
/*** flush.c ***/ #include<stdio.h> #include<string.h> #include<stdlib.h> int main ...
- jquery文章链接
好文链接 1.jQuery是js的一个库,封装了js中常用的逻辑: 2.调用jQuery: (1).本地调用,在script标签的src属性里写上jQuery文件的地址. (2).使用CDN调用jQu ...
- Selenium 的页面加载以及几种等待的问题
1. PageLoadStrategy : 当调用driver.get("https://xxxx.xxx.xxx")来访问某页面时,get方法通常会阻塞浏览器直到页面完全加载后才 ...
- beta week 2/2 Scrum立会报告+燃尽图 06
此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/9959 一.小组情况 组长:贺敬文组员:彭思雨 王志文 位军营 徐丽君队名: ...
- Java如何对一个对象进行深拷贝?
在Java语言里,当我们需要拷贝一个对象时,有两种类型的拷贝:浅拷贝与深拷贝.浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化.而深拷贝则是拷贝了源对象的所有值,所以即 ...
- koa 基础(十四)cookie 的基本使用
1.app.js /** * cookie的简介: * 1.cookie保存在浏览器客户端 * 2.可以让我们用同一个浏览器访问同一个域名的时候共享数据 * * cookie的作用: * 1.保存用户 ...
- https知识汇总
状态码 含义 100 客户端应当继续发送请求.这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝.客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应.服务器必须在 ...
- javascript之DOM(Document Object Model) 文档对象模型
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- 通过TCODE查找SPRO路径
1.SE11:CUS_ACTOBJ,根据OBJECTNAME(对象名称),即视图名称,获取Customizing activity(ACT_ID) 2.根据ACT_ID在表CUS_IMGACT获取说明 ...