首页 > 其他分享 >SPFA最短路

SPFA最短路

时间:2024-02-15 18:11:32浏览次数:22  
标签:松弛 dist 迭代 int 短路 inq SPFA

目录

从Bellman-Ford开始

  • 对于所有边权都大于等于0的图,任意两个顶点之间的最短路,显然不会经过重复的顶点或者边。也就是说任意一条最短路经过的定点数不会超过n个,边不会超过n-1条边
  • 而对于有边权为负的图,有可能图中会存在负环,此时途径负环的最短路没有意义。

核心思想

\(Bellman-Ford\)的核心思想是松弛操作,即对于边\((u,v)\),用\(dist(u)和l(u,v)\)的和尝试更新\(dist(v):\)

\[dist(v)=min(dist(v),dist(u)+l(u,v)) \]

1707988156035.png

\(Bellman-Ford\)所做的,就是不断尝试对图上每一条边进行松弛操作。


我们会进行多次迭代,每进行一次迭代,就对图上所有的边都尝试进行一次松弛操作,当一次迭代中没有点的\(dist\)发生改变时,算法停止。


模拟算法执行过程

1707988734563.png

1707988780511.png

在每次迭代中,遍历所有边,尝试进行松弛操作

1707988890698.png

1707988875714.png


1707988959981.png

1707988972543.png


1707989035910.png

1707989051472.png

因为这里\(B\)还是正无穷,还没找到从起点到\(B\)的最短路,这样通过当前的\(B\)更新其他点是没有意义(这也是后面\(spfa\)优化的关键)


1707989198843.png
1707989215419.png


1707989258889.png
1707989269526.png


1707989296221.png
1707989308610.png


至此第一轮迭代完成,下面是第二轮迭代

1707989412508.png

1707989457679.png

1707989517075.png

第四次迭代已经什么都更新不了了
1707989597426.png

时间复杂度

在最短路存在的情况下(图中不存在负环),由于一次迭代会使最短路的边数至少加\(1\),而\(S\)到每个顶点的最短路经过的边数最多为\(n-1\),因此整个算法最多会进行\(n-1\)轮迭代,每一轮迭代的复杂度为\(O(m)\)(每条边枚举到一次),所以总的时间复杂度为\(O(nm)\)

  • 当从\(S\)点出发能到达一个负环时,就会进行n论以上的迭代

模板

int n, m;       // n表示点数,m表示边数
int dist[N];        // dist[x]存储1到x的最短路距离

struct Edge     // 边,a表示出点,b表示入点,w表示边的权重
{
    int a, b, w;
}edges[M];

// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    // 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < m; j ++ )
        {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            if (dist[b] > dist[a] + w)
                dist[b] = dist[a] + w;
        }
    }

    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    return dist[n];
}

spfa

spfa优化的思想

\(spfa\)是通过队列来优化\(bellman-ford\)算法
在每一次迭代时,只有在上一次迭代中被更新了距离的点,才有可能去更新其他节点。因此,在每一次迭代时,我们将更新过距离的顶点加入一个队列(如果顶点已经在队列里则不加),在下一次迭代时,只需要遍历队列中的顶点连出去的边即可。

  • 在实际实现过程中我们不关心具体是那一次迭代。

模板

vector<vector<pii>>g(n+1);
rep(i,1,m){
	int u,v,w;
	cin>>u>>v>>w;
	g[u].pb({v,w});
	g[v].pb({u,w});
}
vector<vector<int>>inq(n+1);
vector<vector<int>>d(n+1,0x3f3f3f3f);
queue<int>q;
d[1]=0;
inq[1]=1;
q.push(1);
//跑一遍最短路
while(q.size()){
	auto t=q.front();
	q.pop();
	int u=t.x,cnt=t.y;
	inq[u]=0;
	for(auto it:g[u]){
		int v=it.x,w=it.y;
		//松弛操作,或者其他变形具体问题具体分析
		if(满足松弛){
			//更新
			if(!inq[v]){
				inq[v]=1;
				q.push(v);
			}
		}
	}
}

标签:松弛,dist,迭代,int,短路,inq,SPFA
From: https://www.cnblogs.com/cxy8/p/18016365

相关文章

  • 分层图最短路
    分层最短路用更加具体或者形象一点的说法就是有限制的最短路径问题。通常是拆点解决问题,原图中的点加上一个当前点的状态,成为一个新的点P4568[JLOI2011]飞行路线P4568[JLOI2011]飞行路线#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=......
  • 短路在JavaScript中是如何工作的?
    在JavaScript中,理解真实和虚假的值是编写高效简洁代码的基础。结合短路的概念,开发人员可以编写优雅的解决方案来应对常见的编程挑战。在本实践指南中,我们将探讨真实值和虚假值,并了解JavaScript中短路的机制。您可以从这里获取所有源代码。(本文内容参考:java567.com)目录了......
  • 最短路学习笔记
    最短路学习笔记单源最短路径问题(SingleSourceShortestPath,SSSP问题)。Part1DijkstraPart1.0Dijkstra朴素算法洛谷P3371【模板】单源最短路径(弱化版)Dijkstra算法Dijkstra算法的流程如下:初始化$dist[1]=0$,其余节点的$dist$值为正无穷大。找出一个未被标记的......
  • 最短路径
    最短路算法主要有Floyd,Dijkstra,Bellman-Ford,SPFA,Jahnson,A*这六种算法。Floyd用来处理全源最短路,可以处理负边权。时间复杂度为\(\mathcal{O}(N^3)\)。Dijkstra用来处理单源最短路,不能处理负边权。时间复杂度最优为\(\mathcal{O}{(M\logM)}\)。Bellman-Ford用来处理单......
  • 次短路径问题
    一、问题描述P2865[USACO06NOV]RoadblocksG二、问题简析如果求最短路径,我们很自然会想到\(Dijkstra\)。但是,这道题要求的是次短路径。记到\(u\)的最短路径为\(d_1[u]\),到\(u\)的次短路径为\(d_2[u]\)。则\(d_2[v]=d_1[u]+e(u,v)\)or\(d_2[u]+e(u,v).w\)......
  • 最短路径问题
    一、Bellman-Ford算法Q:有一张有\(n\)个点、\(m\)条边的有向图,可能存在重边、负边和自环,但不存在负环,求起点\(s\)到每个点的最短路径。1.1算法简析记图为\(G\);\(G[u]\)表示以\(u\)为起点的所有边的集合;\(e(u,v)\)表示\(u\)到\(v\)的某一条有向边(\(e(u,v)\inG[......
  • 单源正权最短路径——Dijkstra算法
    目录问题引入思路一览算法原理code问题引入给出n点m边,其中边的权值皆为非负数,要求快速给出一个点到其余点的最短距离思路一览dfs遍历维护最短距离floyd算法算全源最短,但是这玩意时间复杂度O(n3),最多也就1000个点左右主角Dijkstra算法算法原理主要是以源点为根节点逐步构......
  • [数论学习笔记01]完系/同余最短路/费马小定理/扩欧/中国剩余定理
    #[数论学习笔记01]完系/同余最短路/费马小定理/扩欧/中国剩余定理###每日蒟蒻小故事(1/1)蒟蒻带了一本崭新的笔记本到S组.他发现这一节课居然在学习数论."听不懂,求讲解!"蒟蒻说.大佬邪魅一笑,并未理会.蒟蒻只能一边听着老师的讲解,一边努力地记着笔记."什么是完全剩余系......
  • 全源最短路径——Floyd算法
    目录问题引入思路一览算法原理代码部分问题引入给出一个含有n个点,m条边的图,如何快速的给出任意两个点的最短路径思路一览这个,感觉没啥思路,可能能想到的最暴力的解法就是对每一个点进行dfs遍历,在遍历过程中更新,但是这样的做法肯定是时间复杂度爆炸的;因此还是老算法Floyd香,Floyd......
  • POJ--2139 Six Degrees of Cowvin Bacon(最短路)
    记录20:342024-2-1http://poj.org/problem?id=2139最短路问题,使用Floyd后遍历选择就可以了。注意是多case输入,答案截尾。#include<cstdio>#include<cstring>#include<iostream>#defineMAX_N305#defineMAX_M10005usingnamespacestd;constintINF=0x3f3f3f3f;......