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. .NET并行计算和并发11:并发接口 IProducerConsumerCollection

    using System; using System.Collections; using System.Collections.Generic; using System.Collections.C ...

  2. 修改权限linux

    1.更改目录所有者命令:chown -R 用户名称 目录名称2.更改目录权限命令:chmod -R 755 目录名称 nginx在不同目录下需要给与全部权限才可以

  3. Java中栈的应用,括号匹配

    package edu.yuliang.Data_Structure_Basics; import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; /* 给 ...

  4. Spring 基于构造函数的依赖注入

    基于构造函数依赖注入 sprig通过bean创建对象时,会通过bean提供的参数来选择调用某个构造函数.上例中, <constructor-arg ref="spellChecker& ...

  5. type() 和 isinstance()区别

    a=111 # type() 返回数据类型 In: type(a)  Out: int In: print(type(a)) Out: <class 'int'> # isinstance ...

  6. Python_02

    Python 判断语句  if,while if ture: print(1) else: print(0) for循环和内嵌函数range() range(a,b,c)   a:起始位置  b:终止 ...

  7. 09_java基础——this

    多次调用同一个对象的某个方法: package com.huawei.test.java04; /** * This is Description * * @author 王明飞 * @date 20 ...

  8. Python多进程并发(multiprocessing)

    1.新建单一进程 如果我们新建少量进程,可以如下: 2.使用进程池 是的,你没有看错,不是线程池.它可以让你跑满多核CPU,而且使用方法非常简单. 注意要用apply_async,如果落下async, ...

  9. webpack 代码分割一点事

    webpack 俨然已经成为前端最主流的构建工具,其功能多种多样,我们今天就来分析下关于代码分割这部分的一点事,并在最后讲述如何实现在webpack编译出的代码里手动添加一个异步chunk. 什么是c ...

  10. 使用min-device-pixel-ratio媒体功能实现真正的1像素border

    关于设备像素比的知识,想必做过移动端开发的都有接触,这里就不介绍啦,万一有不懂的可以看张鑫旭大神的设备像素比devicePixelRatio简单介绍 由于设备像素比存在的原因,我们在处理设计图的一些边 ...