SPFA全面讲解

——最短路高效算法

标签: 最短路

简介:SPFA 是1994年在西安交通大学段凡丁同学所提出,是将Dijsktra以及Bellman-Ford两种最短路算法完美结合的一个算法,效率十分的高。全名为Shortest Path Faster Algorithm,简称SPFA。

首先,在下面的讲解中,我们要用到几个变量:

  1. n 表示一共有n个点。
  2. s 表示开始点。
  3. t 表示结束点。
  4. dist[MAXN]:d[i]表示从s到i的最短路径
  5. head[MAXN]:head[i]记录前驱。
  6. queue\(<int>\)q,也就是队列。
  7. 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:&infin;
a->c:&infin;
a->d:&infin;
a->e:&infin;
a->f:&infin;
a->g:&infin;

然后按照我们的SPFA的顺序,首先a入队,然后判断到队列非空。
将队首元素a出队.

然后对以a点为起始点的所有边进行松弛操作(此处只有e点。)。

此时表格的状态为:

a->a:0
a->b:24
a->c:8
a->d:15
a->e:&infin;
a->f:&infin;
a->g:&infin;

在松弛的时候三个点的最短路径(估值)变小了,然后检测到这些点在队列中还都没有出现。于是入队,此时队列中有了三个点:b,c,d。
然后队首元素c出队.

对以c为起始点的所有边进行松弛操作。

此时表格的状态变为:

a->a:0
a->b:24
a->c:8
a->d:15
a->e:30
a->f:&infin;
a->g:&infin;

此时在列表中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:&infin;

看到了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 全面讲解的更多相关文章

  1. spfa模板+讲解

    zz http://blog.sina.com.cn/s/blog_6ad20aef0100mc1a.html Spfa算法 (模板源代码) 这是Bellman Ford的改进算法.    算法介绍: ...

  2. 图论最短路径算法——Dijkstra

    说实在的,这算法很简单,很简单,很简单--因为它是贪心的,而且码量也小,常数比起SPFA也小. 主要思想 先初始化,dis[起点]=0,其它皆为无限大. 还要有一个bz数组,bz[i]表示i是否确定为 ...

  3. 【算法】祭奠spfa 最短路算法dijspfa

    题目链接 本题解来源 其他链接 卡spfa的数据组 题解堆优化的dijkstra 题解spfa讲解 来自以上题解的图片来自常暗踏阴 使用前向星链表存图 直接用队列优化spfa struct cmp { ...

  4. 觉得一篇讲SPFA还不错的文章

    我觉得他整理的有一些乱,我都改成插入代码了,看的顺眼一些 转载自http://blog.csdn.net/juststeps/article/details/8772755 下面的都是原文: 最短路径 ...

  5. 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)

    这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...

  6. POJ3169--Layout(SPFA+差分系统)

    Description Like everyone else, cows like to stand close to their friends when queuing for feed. FJ ...

  7. 关于$NOIP2017$的题目讲解

    关于\(NOIP2017\)的题目讲解 1.小凯的疑惑 题目描述: 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法 ...

  8. 【最短路径】 SPFA算法

    上一期介绍到了SPFA算法,只是一笔带过,这一期让我们详细的介绍一下SPFA. 1 SPFA原理介绍 SPFA算法和dijkstra算法特别像,总感觉自己讲的不行,同学说我的博客很辣鸡,推荐一个视频讲 ...

  9. 算法提高 道路和航路 SPFA 算法

    我简单的描述一下题目,题目中所说的有道路和航路: 1.公路是双向的,航路是单向的: 2.公路是正值,航路可正可负: 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1 ...

随机推荐

  1. android应用签名详解

    1.Eclipse工程中右键工程,弹出选项中选择 android工具-生成签名应用包: 2.选择需要打包的android项目工程: 3.如果已有私钥文件,选择私钥文件 输入密码,如果没有私钥文件见 第 ...

  2. [實現DDD] 第10章 聚合(1)設計原則

    聚合只是將一些實體(Entity)與值對象(Value Object)聚集起來的對象樹嗎?? 有些途徑可能使我們設計出不正確的聚合模型, 如:可能為了對象組合上的方便而將聚合設計的很大;也可能設計的聚 ...

  3. xss攻击汇总--转

    (1)普通的XSS JavaScript注入<SCRIPT SRC=http://3w.org/XSS/xss.js></SCRIPT>(2)IMG标签XSS使用JavaScr ...

  4. NDK编译不同架构的参数

    随着Android的蓬勃发展, CPU的架构也越来越多. 早期只支持ARMv5, 截至目前, 支持的架构已达三类七种: ARM(ARMv5,ARMv7 (从2010年起),ARMv8), x86(x8 ...

  5. phpstorm主题设置

    毫无疑问,phpstorm很好用,但是安装完成后自带的主题,丑的一匹,所以总结下如何更换主题............. 1.主题下载位置 http://www.phpstorm-themes.com ...

  6. FontAwesome 图标 class="fa fa-home"

    本文转自:http://www.yeahzan.com/fa/facss.html 引用方式: class="fa fa-home" 注意:每个图标的引用都必须要添加 fa fa- ...

  7. ASP.NET安全[开发ASP.NET MVC应用程序时值得注意的安全问题](转)

    概述 安全在web领域是一个永远都不会过时的话题,今天我们就来看一看一些在开发ASP.NET MVC应用程序时一些值得我们注意的安全问题.本篇主要包括以下几个内容 : 认证 授权 XSS跨站脚本攻击 ...

  8. Paxos、ZAB、RAFT协议

    这三个都是分布式一致性协议,ZAB基于Paxos修改后用于ZOOKEEPER协议,RAFT协议出现在ZAB协议之后,与ZAB差不多,也有很大区别. 1. Paxos 分布式节点分为3种角色, Prop ...

  9. js之正则表达式基础

    字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在.比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦, ...

  10. oracle相关常识

    1.数据类型 VARCHAR2() NUMBER() DATE CLOB BLOB 2.复制表:create table tableName as select * from emp3.新增列:ALT ...