# 概述
SPFA算法O(kE,k是常数,平均值为2,是Bellman-Ford算法的队列实现),Bellman-Ford算法主要是处理负权边问题,但无法处理负回路,只能判断是否为负环。
算法描述
dis数组用来存储从源点到各个点的路径长度,vis用来标记是否已经被走过,这里注意,每次取出队头元素,对所有点进行遍历时要对每个点进行标记,但处理完之后要把对头元素重新标记为true,这样才不会影响下面的计算,这里还可以进行优化,可以用DFS进行深搜,这样可以将复杂度减少至O(N)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f; //inf表示无穷大
int num[maxn];
int dis[maxn];
bool vis[maxn];
int n,m;
struct node // v表示终点,w表示边权
{
int v,w;
node(int vv,int ww):v(vv),w(ww){}
};
vector <node> e[maxn];
queue <int> q;
void add_edge(int u , int v , int w) //用来添加边
{
e[u].push_back(node(v,w));
}
void init() //初始化数据,对图进行添加边,连通图
{
cin >> n >> m;
for(int i = 0 ; i < m ; i++)
{
int u,v,w;
cin >> u >> v >> w;
add_edge(u,v,w); //这里注意要添加两次,因为有些题目的路径是双向的
add_edge(v,u,w);
}
}
void spfa(int st,int ed) //st表示源点 ed表示终点
{
fill(vis,vis+maxn,false); // 初始化vis数组为false
fill(dis,dis+maxn,inf); // 初始化dis数组为inf
q.push(st); //将起点入队
dis[st] = 0;
vis[st] = true; //标记源点
while(!q.empty())
{
int u = q.front();
q.pop();
for(unsigned int i = 0 ; i < e[u].size() ; i++) //遍历所有与u有连接的路线
{
int v = e[u][i].v;
int w = e[u][i].w;
if(dis[v] > dis[u] + w) //对路径进行松弛,更新最短路径
{
dis[v] = dis[u] + w;
if(!vis[v])
{
q.push(v); //入队标记
vis[v] = true;
}
}
}
vis[u] = false; //切记要把u重新标记
}
cout << dis[ed] << endl;
}
int main()
{
init();
spfa(1,n);
return 0;
}
I'm so cute. Please give me money.
- 本文链接:http://yoursite.com/2019/09/06/%E5%9B%BE%E8%AE%BA----%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84(Spfa%E7%AE%97%E6%B3%95)/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub IssuesGitHub Discussions