spfa求最短路径,其思想就是遍历每一个点,将没有入队的点入队,从这个点开始不断修改能够修改的最小路径,直到队空。不过这里一个点可以重复入队。

这个需要有存图的基础--------->前向星存图

举个栗子

  

这里有一张图,边旁边的数字为这条边的权值。旁边的图为边的编号

用dis[i]来记录起点到i的最小路径长度(一开始都是inf)

求最小路径,首先从起点开始,遍历起点的每一条出边,并将要修改dis[i]的出边终点(没有入队的点)入队,再不断出队,对每个队中的点进行相同的操作。

模拟一下。

首先将①入队。dis[1]=0。①的第一条出边的终点是②,将②入队,同时修改dis[2]=3.

下一条出边是第四条边,终点为③,将③入队,修改dis[3]=4.

将④入队,dis[4]=6。

进行完这一步,①出队,同时将①标记为未入队,对②进行操作。

②的第一条出边的终点为①,不修改,不入队。

next:终点为③,9+3>4,不修改 ,不入队。

next:将⑥入队,dis[6]=10+3=13

如此不断更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

来我们看一下代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#define spfa zhx_akioi
using namespace std;
long long n,m,s,head[],num;
long long dis[],vis[];
queue <long long> q;
const int inf=;
struct Edge{
int next,to,dis;
}edge[];
void add(int f,int t,int d)
{ num++;
edge[num].next=head[f];
edge[num].to=t;
edge[num].dis=d;
head[f]=num;
}
void spfa()
{ for(int i=;i<=n;i++)
dis[i]=inf;//最开始先把每个点到起点的距离设为无限大
dis[s]=;//起点到起点的距离是0
vis[s]=;//将起点入队,用vis标记是否在队里
q.push(s);
while(!q.empty())
{int u=q.front();
q.pop();
vis[u]=;
for(int i=head[u];i;i=edge[i].next)//从出队的点开始,遍历这个点的每条出边
{ int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)//如果这个点当前到起点的距离大于出队的点到起点的距离加上当前边的距离,即可以更新,就更新,并将更新的点入队
{ dis[v]=dis[u]+edge[i].dis;
if(vis[v]==)
{q.push(v);
vis[v]=;//标记
}
}
}
}
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=;i<=m;i++)
{int f,t,d;
scanf("%lld%lld%lld",&f,&t,&d);
add(f,t,d);//存图
}
spfa();
for(long long i=;i<=n;i++)
printf("%lld ",dis[i]);
}

判负环

如果图里面没有负环,那么一个点最多入队n次。如果有点入队次数大于n次就说明有负环。

当然还可以把spfa改成dfs版,即一直沿着某条路进行更新,如果再一次松弛到了该路径上松弛过的点,就证明有负环(可能会TLE)

bfs版:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define pa pair<int,int>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=;
inline ll read()
{
char ch=getchar();
ll x=;
bool f=;
while(ch<''||ch>'')
{
if(ch=='-') f=;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return f?-x:x;
}
int t,n,m,head[],cnt,dis[],vis[],in[];
struct E{
int to,nxt,dis;
}ed[];
void init()
{
cnt=;
memset(head,,sizeof(head));
memset(in,,sizeof(in));
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
}
void add(int fr,int to,int dis)
{
ed[++cnt].to=to;
ed[cnt].dis=dis;
ed[cnt].nxt=head[fr];
head[fr]=cnt;
}
bool spfa()
{
queue <int> q;
dis[]=;
vis[]=;
in[]++;//in统计入队次数
q.push();
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=;
for(int e=head[u];e;e=ed[e].nxt)
{
int v=ed[e].to;
if(dis[v]>dis[u]+ed[e].dis)
{
dis[v]=dis[u]+ed[e].dis;
if(!vis[v])
{
vis[v]=;
in[v]++;
if(in[v]>n) return ;
q.push(v);
}
}
}
}
return ;
}
int main()
{
t=read();
while(t--)
{
init();
n=read();m=read();
for(int i=;i<=m;i++)
{
int fr=read(),to=read(),dis=read();
add(fr,to,dis);
if(dis>=)
add(to,fr,dis);
}
if(spfa()) printf("YE5\n");//模板题让你输出的奇奇怪怪的东西
else printf("N0\n");
}
}

dfs版:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define pa pair<int,int>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=;
inline ll read()
{
char ch=getchar();
ll x=;
bool f=;
while(ch<''||ch>'')
{
if(ch=='-') f=;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return f?-x:x;
}
int t,n,m,head[],cnt,dis[],vis[],in[];
int sta[],top;
bool fh;
struct E{
int to,nxt,dis;
}ed[];
void init()
{
cnt=;top=;fh=;
memset(head,,sizeof(head));
memset(in,,sizeof(in));
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
}
void add(int fr,int to,int dis)
{
ed[++cnt].to=to;
ed[cnt].dis=dis;
ed[cnt].nxt=head[fr];
head[fr]=cnt;
}
void spfa(int u)
{
if(fh) return ;
vis[u]=;
for(int e=head[u];e;e=ed[e].nxt)
{
if(fh) return ;
int v=ed[e].to;
if(dis[v]>dis[u]+ed[e].dis)
{
dis[v]=dis[u]+ed[e].dis;
if(vis[v])
{
fh=;
return;
}
spfa(v);
}
}
vis[u]=;
}
int main()
{
t=read();
while(t--)
{
init();
n=read();m=read();
for(int i=;i<=m;i++)
{
int fr=read(),to=read(),dis=read();
add(fr,to,dis);
if(dis>=)
add(to,fr,dis);
}
dis[]=;
spfa();
if(fh) printf("YE5\n");
else printf("N0\n");
}
}

Spfa求最短路径的更多相关文章

  1. SPFA求单源最短路径

    序 求最短路径的算法有很多,各有优劣. 比如Dijkstra(及其堆(STL-priority_queue)优化),但是无法处理负环的情况: 比如O(n^3)的Floyd算法:比如Bellman-Fo ...

  2. POJ 1860 Currency Exchange / ZOJ 1544 Currency Exchange (最短路径相关,spfa求环)

    POJ 1860 Currency Exchange / ZOJ 1544 Currency Exchange (最短路径相关,spfa求环) Description Several currency ...

  3. 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径

    自从打ACM以来也算是用Dijkstra算法来求最短路径了好久,现在就写一篇博客来介绍一下这个算法吧 :) Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的 ...

  4. 求最短路径算法之SPAF算法。

    关于求最短路径: 求最短路径的算法有许多种,除了排序外,恐怕是OI界中解决同一类问题算法最多的了.最熟悉的无疑是Dijkstra(不能求又负权边的图),接着是Bellman-Ford,它们都可以求出由 ...

  5. SPFA算法——最短路径

    粗略讲讲SPFA算法的原理,SPFA算法是1994年西南交通大学段凡丁提出 是一种求单源最短路的算法 算法中需要用到的主要变量 int n;  //表示n个点,从1到n标号 int s,t;  //s ...

  6. POJ 2387 Til the Cows Come Home Dijkstra求最短路径

    Til the Cows Come Home Bessie is out in the field and wants to get back to the barn to get as much s ...

  7. ACM - 最短路 - AcWing 851 spfa求最短路

    AcWing 851 spfa求最短路 题解 以此题为例介绍一下图论中的最短路算法 \(Bellman\)-\(Ford\) 算法.算法的步骤和正确性证明参考文章最短路径(Bellman-Ford算法 ...

  8. C++迪杰斯特拉算法求最短路径

    一:算法历史 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是以 ...

  9. spfa求最长路

    http://poj.org/problem?id=1932 spfa求最长路,判断dist[n] > 0,需要注意的是有正环存在,如果有环存在,那么就要判断这个环上的某一点是否能够到达n点,如 ...

随机推荐

  1. C# 保存屏幕截图

    //屏幕宽 int iWidth = Screen.PrimaryScreen.Bounds.Width; //屏幕高 int iHeight = Screen.PrimaryScreen.Bound ...

  2. logback-MDC日志唯一标识

    自定义LogbackFilter: import org.slf4j.MDC; import javax.servlet.*; import javax.servlet.annotation.WebF ...

  3. SQL server 的身份验证模式

    windows身份验证(本机的ip地址或者localhost 或者.或者127.0.0.1) SQL Server身份验证(用户名和密码登录) 常见的错误代码18456(登录失败)和18470(账户被 ...

  4. 【论文阅读】Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks

    Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks 参考 1. 人脸关键点: 2. ...

  5. linux服务器ssh免密登录

    环境:两台服务器,Park01.Park02,配置ssh免密登录 在Park01执行:ssh-keygen 然后一直回车 生成节点的公钥和私钥,生成的文件会自动放在/root/.ssh目录下   然后 ...

  6. 《Java编程思想》读书笔记-赋值操作符

    在最底层,Java中的数据是通过使用操作符来操作的.接下来我们逐一认识一些操作符. 怎么运用操作符 操作符接受一个或多个参数,并生成一个新值. 基本操作符 赋值操作符 符号:= 作用:取右边的值,把它 ...

  7. light sdk

    //请求ajax var request = function (url,method,params,cb) { var d = ajax({ url:url, type:method, data:p ...

  8. word中编辑论文公式对齐问题

    这里只说在word中编辑公式时,公式居中,编号右对齐的情况. 在编辑公式时,我平时就是右对齐,然后通过敲击空格键进行公式的居中,然而这样并不美观.所以接下来学习一下: 1)首先打开视图-->标尺 ...

  9. Python3.7和数据库MySQL 8.0.12 数据库数据驱动mysql-connector安装(四)

    安装mysql-connector驱动 在系统CMD输入命令: pip install mysql-connector 示例: 创建数据库 # 导入驱动 import mysql.connector ...

  10. Virtualbox 虚拟机安装Linux

    背景:Win10系统   MSI主板 目标:基于Win10 利用虚拟机Virtualbox安装Linux 准备工作:Ctrl+Alt+Del打开任务管理器——>性能(查看CPU虚拟化是否开启) ...