C++ 最短路SPFA
算法描述:
对于图 G = <V, E>,源点为s,d[i]表示s到i的最短路。
(1)利用一个先进先出的队列来保存待松弛的节点,每次取出队首u,并且枚举从u出发的所有点(u,v),进行松弛操作:
d[v] = min(d[v], d[u] + w(u, v))
(2)然后判断v在不在队列中,如果不在就将v放入队列中。这样不断从队列中取出结点来进行松弛操作,直到队列为空为止
代码分析:
第一步,定义边的数据结构 Edge(v, w)
第二步,边的添加,
function addEdge(edges[maxn], u, v, w)
edges[u].append(Edge(v, w))
第三步,建图
addEdge(edges, u1, v1, w1)
addEdge(edges, u2, v2, w2)
...
第四步,SPFA框架代码
function SPFA(n, s, edges[maxn], d[maxn], visited[maxn])
q = Queue()
inq = {}
SPFAinit(n, s, d, visited, q, inq)
while(not q.empty())
u = q.front()
q.pop()
inq.remove(u)
if visited[u]++ > n
return true
SPFArelax(u, edges, d, q, inq)
return false
第五步,SPFA初始化
function SPFAinit(n, s, d[maxn], visited[maxn], q, inq)
for i -> (0, n-1)
d[i] = inf
visited[i] = 0
d[s] = 0
visited[s] = 1
q.push(s)
inq.add(s)
第六步,实现松弛操作
function SPFARelax(u, edges[maxn], d[maxn], q, inq)
for i-> (0, edges[u].size() - 1)
v, w = edges[u][i]
if d[u] + w < d[v]
d[v] = d[u] + w
if not inq.has(v)
q.push(v)
inq.add(v)
SPFA的最长时间复杂度为km,k为常数,m为边数
代码练习,对应蓝桥云课 路径 代码见下
#include <iostream>
#include <vector>
#include <queue>
using namespace std;#define maxn 2022
#define maxm (2022*2*22)
#define eType int
#define inf 1000000000
#define longOrShortpath <struct EDGE{int v;eType w;EDGE() {}EDGE(int _v, eType _w){v = _v;w = _w;}
};void initEdges(int n, vector<EDGE> edges[maxn]){for(int i=0; i<=n; ++i){edges[i].clear();}
}void addEdge(vector<EDGE> edges[maxn], int u, int v, eType w){edges[u].push_back(EDGE(v, w));
}void SPFAinit(int n, int s, eType dist[maxn], queue<int>& q, bool inqueue[maxn]){for(int i=0; i<=n; ++i){dist[i] = (i == s) ? 0:inf;inqueue[i] = false;}inqueue[s] = true;q.push(s);}void SPFAupdate(vector<EDGE> edges[maxn], int u, eType dist[maxn], queue<int>& q, bool inqueue[maxn]){for(int i=0; i<edges[u].size(); ++i){int v = edges[u][i].v;eType w = edges[u][i].w;if(dist[u] + w longOrShortpath dist[v]){dist[v] = dist[u] + w;if(!inqueue[v]){inqueue[v] = true;q.push(v);}}}
}void SPFA(vector<EDGE> edges[maxn], int n, int s, eType dist[maxn]){queue<int> q;bool inqueue[maxn];SPFAinit(n, s, dist, q, inqueue);while(!q.empty()){int u = q.front();q.pop();inqueue[u] = false;SPFAupdate(edges, u, dist, q, inqueue);}
}
vector<EDGE> edges[maxn];
eType dist[maxn];int gcd(int a, int b){return !b ? a:gcd(b, a%b);
}int lcm(int a, int b){return a/gcd(a, b) * b;
}int main()
{int n = 2021;initEdges(n, edges);for(int i=1; i <= n; ++i){for(int j=1; j - i <= 21; ++j){if(i-j > 21) continue;if (j > n) break;addEdge(edges, i, j, lcm(i, j));}}SPFA(edges, n, 1, dist);cout << dist[n] << endl;// 请在此输入您的代码return 0;
}
代码练习 2 对应蓝桥云课 地铁最短路径与最少换乘
#include <iostream>
using namespace std;
#include <vector>
#include <queue>
using namespace std;#define maxn 100001
#define eType int
#define inf 1000000000
#define longOrShortpath <struct EDGE{int v;eType w;EDGE() {}EDGE(int _v, eType _w){v = _v;w = _w;}
};void initEdges(int n, vector<EDGE> edges[maxn]){for(int i=0; i<=n; ++i){edges[i].clear();}
}void addEdge(vector<EDGE> edges[maxn], int u, int v, eType w){edges[u].push_back(EDGE(v, w));
}void SPFAinit(int n, int s, eType dist[maxn], queue<int>& q, bool inqueue[maxn]){for(int i=0; i<=n; ++i){dist[i] = (i == s) ? 0:inf;inqueue[i] = false;}inqueue[s] = true;q.push(s);}void SPFAupdate(vector<EDGE> edges[maxn], int u, eType dist[maxn], queue<int>& q, bool inqueue[maxn]){for(int i=0; i<edges[u].size(); ++i){int v = edges[u][i].v;eType w = edges[u][i].w;if(dist[u] + w longOrShortpath dist[v]){dist[v] = dist[u] + w;if(!inqueue[v]){inqueue[v] = true;q.push(v);}}}
}void SPFA(vector<EDGE> edges[maxn], int n, int s, eType dist[maxn]){queue<int> q;bool inqueue[maxn];SPFAinit(n, s, dist, q, inqueue);while(!q.empty()){int u = q.front();q.pop();inqueue[u] = false;SPFAupdate(edges, u, dist, q, inqueue);}
}
vector<EDGE> edges[maxn];
eType dist[maxn];
#define maxm 200001int u[maxm], v[maxm], w[maxm];int main()
{int n, m;cin >> n >> m;for(int i=0; i<m; ++i){cin >> u[i] >> v[i] >> w[i];}int s, d;cin >> s >> d;initEdges(n, edges);for(int i=0; i<m; ++i){addEdge(edges, u[i], v[i], w[i]);addEdge(edges, v[i], u[i], w[i]);}SPFA(edges, n, s, dist);if(dist[d] == inf){dist[d] = -1;}cout << dist[d] << endl;initEdges(n, edges);for(int i=0; i<m; ++i){addEdge(edges, u[i], v[i], 1);addEdge(edges, v[i], u[i], 1);}SPFA(edges, n, s, dist);if(dist[d] == inf){dist[d] = -1;}cout << dist[d] << endl;// 请在此输入您的代码return 0;
}