数据结构与算法学习笔记----SPFA算法
@@ author: 明月清了个风
@@ first publish time: 2024.12.19
SPFA算法
这同样是一种单源最短路径算法,是队列优化的Bellman-ford算法,因此他能处理的情况和Bellman-ford算法一样,但是在一般情况下,时间复杂度更低,为 O ( m ) O(m) O(m), m m m为边数,最坏情况为 O ( n m ) O(nm) O(nm)。
基本思想
spfa的思想和bellman-ford算法一样。
可以发现bellman-ford算法在松弛操作时比较无脑,会遍历所有边进行遍历,但其实如果对于一个边 ( a , b ) (a,b) (a,b)来说,如果更新的话说明有 d i s t [ b ] > d i s t [ a ] + w ( a , b ) dist[b] > dist[a] + w(a,b) dist[b]>dist[a]+w(a,b),如果在这一轮中 d i s t [ a ] dist[a] dist[a]没有变,那么 d i s t [ b ] dist[b] dist[b]也不会变,因此这里可以考虑使用优化dijkstra的方法优化bellman-ford算法,也就是队列优化,具体的看代码吧,代码和dijkstra很像, 加入了比较详细的注释。
这里的无法到达判断和bellman-ford不一样,直接判断是否dist[n] == inf
即可,因为每一次更新都肯定是能够从源点到达的点,而不是所有的边。
Acwing 853. 有边数限制的最短路
[原题链接](853. 有边数限制的最短路 - AcWing题库)
给定一个 n n n个点 m m m条边的有向图,图中可能存在重边和自环,边权可能为负数。
请你求出 1 1 1号点到 k k k号点的最多经过 k k k条边的最短距离,如果无法从 1 1 1号点走到 n n n号点,则输出 i m p o s s i b l e impossible impossible。
注意:图中可能出现负权回路。
输入格式
第一行包含三个整数 n n n, m m m, k k k。
接下来 m m m行,每行包含三个整数 x x x、 y y y、 z z z,表示存在一条从点 x x x到点 y y y的有向边,边长为 z z z。
输出格式
输出一个整数,表示 1 1 1号点到 n n n号点的最多经过 k k k条边的最短距离。
如果无法从 1 1 1号点走到 n n n号点,则输出 i m p o s s i b l e impossible impossible。
数据范围
1 ≤ n , k ≤ 500 1 \leq n,k \leq 500 1≤n,k≤500,
1 ≤ m ≤ 10000 1 \leq m \leq 10000 1≤m≤10000,
1 ≤ x , y ≤ n 1 \leq x, y \leq n 1≤x,y≤n,
图中涉及边长均不超过10000。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int N = 100010, inf = 0x3f3f3f3f;
int dist[N];
int h[N], w[N], e[N], ne[N], idx;
bool st[N]; // 用来记录点的距离是否被更新了,若距离更新则加入队列并置1.
int n, m;
void add(int a, int b, int c) // 邻接表加边操作
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int spfa()
{
memset(dist, 0x3f, sizeof dist); // 初始化距离
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true; // 源点入队
while(q.size())
{
int t = q.front(); // 取出队头
q.pop();
st[t] = false; // 处理后置0
for(int i = h[t]; i != -1; i = ne[i]) // 遍历出边,更新距离。
{
int j = e[i];
if(dist[j] > dist[t] + w[i]) // 判断更新条件
{
dist[j] = dist[t] + w[i];
if(!st[j]) // 若更新了但没在更新队列中,就加入队列。
{
q.push(j);
st[j] = true;
}
}
}
}
return dist[n];
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for(int i = 0; i < m; i ++)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
int t = spfa();
if(t == inf) puts("impossible");
else cout << t << endl;
return 0;
}
标签:dist,int,SPFA,ford,----,leq,算法,号点
From: https://blog.csdn.net/weixin_60278491/article/details/144578522