【模板】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] ...
随机推荐
- POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
- Python和Sublime的整合
按照下面的方式也可以运行py代码,但是交互方式不是很好,主要简单介绍了一下Python和Sublime的整合 一 Ctrl + B 二 SublimeREPL 安装SublimeREPL 1.打开P ...
- bootstrap面板的使用
<div class="panel panel-primary"> <div class="panel-heading"> 头部 < ...
- Java内存和垃圾回收
Java内存大体上可以分为:本地方法区(线程共享).Java栈(线程隔离).本地方法栈(线程隔离).Java堆(线程共享).程序计数器(线程隔离). 1.本地方法区 各个线程共享的内存区域,只要存放被 ...
- mongodb远程链接命令
mongo 172.17.0.170:27017/spider_data -u admin -p 然后输入密码 切换数据库 use spider_data 查看所有表 show tables
- NDK OpenGLES3.0 开发(五):FBO 离屏渲染
什么是 FBOFBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加了纹理或者 ...
- LeetCode 82. 删除排序链表中的重复元素 II(Remove Duplicates from Sorted List II)
题目描述 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4->4->5 输出: ...
- Springboot websocket使用
1)基本概念 1.http与websocket http超文本传输协议,大家都非常熟悉,http有1.0.1.1. 2.0几个版本,从http1.1起,默认都开启了Keep-Alive,保持连接持续性 ...
- 学习笔记01:《开放平台产品成长之路-POP》
当看到一些比较好的书籍和视频内容时,希望自己可以总价归纳下来,一方面是好的东西希望可以分享给大家,另一方面希望自己能很好的吸收并转化成掌握的知识,所以有了这个系列的学习笔记,共勉,今天的你比昨天更博学 ...
- DP&图论 DAY 5 上午
DP&图论 DAY 5 上午 POJ 1125 Stockbroker Grapevine 有 N 个股票经济人可以互相传递消息,他们之间存在一些单向的通信路径.现在有一个消息要由某个人开 ...