一种最短路求法(个人觉得比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(不完全详解)的更多相关文章

  1. 高性能JavaScript模板引擎实现原理详解

    这篇文章主要介绍了JavaScript模板引擎实现原理详解,本文着重讲解artTemplate模板的实现原理,它采用预编译方式让性能有了质的飞跃,是其它知名模板引擎的25.32 倍,需要的朋友可以参考 ...

  2. OpenCV模板匹配函数matchTemplate详解

    参考文档:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matchin ...

  3. Javascript模板引擎mustache.js详解

    mustache.js是一个简单强大的Javascript模板引擎,使用它可以简化在js代码中的html编写,压缩后只有9KB,非常值得在项目中使用.本文总结它的使用方法和一些使用心得,内容不算很高深 ...

  4. *ecshop 模板中foreach用法详解

    1.foreach分以下几个参数 from, item, name, iteration, index 2.使用foreach循环      如果php要传递一个数组(如:$array)给ecshop ...

  5. ThinkPHP模板IF标签用法详解

    投稿:shichen2014 字体:[增加 减小] 类型:转载 时间:2014-07-01 我要评论 这篇文章主要介绍了ThinkPHP模板IF标签用法,需要的朋友可以参考下 ThinkPHP的IF标 ...

  6. Python时间获取详解,Django获取时间详解,模板中获取时间详解(navie时间和aware时间)

    1.Python获取到的时间 import pytz from datetime import datetime now = datetime.now() # 这个时间为navie时间(自己不知道自己 ...

  7. Ecshop模板中html_options用法详解

    程序部分 <?php $smarty->assign('status_list', $_LANG['cs']); // 订单状态 $smarty->display("ind ...

  8. 【Python-Django】Jinja2模板引擎配置教程详解!!!!

    Jinjia2的官方文档:http://jinja.pocoo.org/docs/2.10/ 1. 安装Jinja2扩展包 $ pip install Jinja2 2. 配置Jinja2模板引擎 T ...

  9. Bellman-ford算法与SPFA算法思想详解及判负权环(负权回路)

    我们先看一下负权环为什么这么特殊:在一个图中,只要一个多边结构不是负权环,那么重复经过此结构时就会导致代价不断增大.在多边结构中唯有负权环会导致重复经过时代价不断减小,故在一些最短路径算法中可能会凭借 ...

  10. 帝国CMS模板$GLOBALS[navclassid]用法详解

    帝国CMS模板程序扩展变量说明:通过这些变量可实现各种更复杂的显示格式. 一.列表/封面模板变量说明:(栏目页或专题页中使用) (一).当前栏目ID或专题ID:$GLOBALS[navclassid] ...

随机推荐

  1. svn版本更新

    1.查看当前版本:svn --version 2.配置svn yum源 tee /etc/yum.repos.d/wandisco-svn.repo <<-'EOF' [WandiscoS ...

  2. sql 用表组织数据

    一.四种完整性约束 1.实体完整性约束:不允许出现相同记录的数据 2.域完整性约束:对字段进行限定,不得插入不符合限定的数据 3.引用完整性:表与表之间的关系 4.自定义完整性约束:开发人员自己设定对 ...

  3. HDU6140--Hybrid Crystals(思维)

    Hybrid Crystals Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  4. 消费端ACK和重回队列

    使用场景 消费端ACK和重回队列 消费端ACK使用场景: 1.消费端进行消费的时候,如果由于业务异常我们可以进行日志记录,然后进行补偿. 2.由于服务器宕机等严重问题,那我们就需要手工进行ACK保障消 ...

  5. 【知识库】-数据库_MySQL之高级数据查询:去重复、组合查询、连接查询、虚拟表

    简书作者:seay 文章出处: 关系数据库SQL之高级数据查询:去重复.组合查询.连接查询.虚拟表 回顾:[知识库]-数据库_MySQL之基本数据查询:子查询.分组查询.模糊查询 Learn [已经过 ...

  6. CodeForces 707D Persistent Bookcase ——(巧妙的dfs)

    一个n*m的矩阵,有四种操作: 1.(i,j)处变1: 2.(i,j)处变0: 3.第i行的所有位置1,0反转: 4.回到第k次操作以后的状态: 问每次操作以后整个矩阵里面有多少个1. 其实不好处理的 ...

  7. Xargs用法详解(自创)

    简介之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,例如: 这个命令是错误的find /sbin -perm +700 |ls -l ...

  8. 解决Vue刷新一瞬间出现样式未加载完或者出现Vue代码问题

    解决Vue刷新一瞬间出现样式未加载完或者出现Vue代码问题: <style> [v-cloak]{ display: none; } </style> <div id=& ...

  9. uimgr 子控件主动往管理类注册自己

    /// <summary> /// 供UIBehaviour调用,UIBehaviour每个控件都会动态挂载,并且在awake里面调用,注册自己 /// </summary> ...

  10. Linux :vim 模式下的常用命令

    [参考文章]:vim 复制一整行 复制多行 1. 查找命令 ?text    查找text,按n健查找下一个,按N健查找前一个 /text     反向查找text,按n健查找下一个,按N健查找前一个 ...