SPFA(Shortest Path Faster Algorithm)算法是一种用于求解单源最短路径问题的图算法。它与Dijkstra算法类似,但更适用于存在负权边的情况。下面详细解释SPFA算法的原理和步骤:
基本原理: SPFA算法是一种广度优先搜索(BFS)的变种,用于寻找从源点到其他所有点的最短路径。它的核心思想是通过松弛操作逐步缩小每个顶点到源点的估计距离,直到找到最短路径或确定没有更短路径。
步骤:
初始化:将源点的最短距离初始化为0,其他点的最短距离初始化为无穷大(通常用一个足够大的数表示)。然后将源点入队。
进行松弛操作:从队列中取出一个点,遍历其所有邻接点,尝试通过这个点获得更短的路径。如果通过该点可以获得更短的距离,就进行松弛操作。即,如果 dist[u] + weight < dist[v]
,其中 u
为当前点,v
为邻接点,dist[u]
表示从源点到 u
的距离,weight
表示边 (u, v)
的权重,那么更新 dist[v] = dist[u] + weight
。
将更新的点入队:如果通过松弛操作更新了某个点 v
的最短距离,将 v
入队,以便继续扩展从 v
出发的路径。
重复步骤2和步骤3,直到队列为空。这个过程类似于BFS,通过不断松弛和入队,最终确定了每个点到源点的最短距离。
结果:在算法结束后,dist[i]
存储了源点到顶点 i
的最短距离。如果 dist[i]
仍然是初始值(无穷大),表示从源点无法到达顶点 i
。
注意事项:
SPFA算法在实际应用中非常有用,特别是在求解具有负权边的最短路径问题。
cpp#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f; // 无穷大常数,可以根据实际情况调整
struct Edge {
int to, weight;
Edge(int _to, int _weight) : to(_to), weight(_weight) {}
};
vector<vector<Edge>> graph; // 图的邻接表
vector<int> dist; // 存储从源点到各个点的最短距离
void spfa(int source) {
int n = graph.size(); // 顶点数
dist.assign(n, INF); // 初始化距离为无穷大
dist[source] = 0; // 源点到自身的距离为0
queue<int> q;
vector<bool> in_queue(n, false); // 记录顶点是否在队列中
q.push(source);
in_queue[source] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
in_queue[u] = false;
for (Edge& edge : graph[u]) {
int v = edge.to;
int weight = edge.weight;
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
if (!in_queue[v]) {
q.push(v);
in_queue[v] = true;
}
}
}
}
}
int main() {
int n, m; // 顶点数和边数
cin >> n >> m;
graph.resize(n);
for (int i = 0; i < m; ++i) {
int u, v, weight;
cin >> u >> v >> weight;
graph[u].emplace_back(v, weight);
graph[v].emplace_back(u, weight); // 如果是无向图,需要加上反向边
}
int source; // 源点
cin >> source;
spfa(source);
for (int i = 0; i < n; ++i) {
cout << "Shortest distance from " << source << " to " << i << " is: " << dist[i] << endl;
}
return 0;
}
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!