SPFA算法
简介:
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。
算法的实现步骤
实现spfa算法需要一个队列q,一个标记数组vis[N]用来标记某点是否在队列中。数组dist[N],用来存储起点到某个点的最短距离。
- 初始化dist数组为正无穷
- 从起点开始枚举每个点的所有子节点,设父节点到子节点的距离为w,父节点到起点的距离为dist[u],子节点到起点的距离为dist[v],如果
dist[u]+w>dist[v] - 当且仅当上式成立时就更新dist[v],如果v没有在队列中,就将v入队。
例子:
给出一个有向图,请输出从某一点出发到所有点的最短路径长度
输入格式
第一行包含三个整数 n,m,s,分别表示点的个数、有向边的个数、出发点的编号。
接下来 mm 行每行包含三个整数 u,v,w,表示一条 u→v 的,长度为 w 的边。
输出格式
输出一行 nn个整数,第 ii 个表示 ss 到第 ii 个点的最短路径,若不能到达则输出-1
输入样例
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出样例
0 2 4 3
- 首先初始化,将vis[]赋值为0,dis[]赋值为无穷。然后将起点1入队,将vis[1]=1,dis[1]=0。
- 将队列的头元素1从队列中取出,遍历他的子节点(2,3,4),由于dis[2]>dis[1]+2,更新
dis[2]=dis[1]+2,以此类推,更新dis[3]=dis[1]+5,dis[4]=dis[1]+4,将(2,3,4)入队,vis[2]=1,vis[3]=1,vis[4]=1
3.将队列中的头元素2取出,并将vis[2]=0,遍历2的子节点(3,4)。
由于dis[3]>dis[2]+2,dis[3]=dis[2]+2,由于vis[3]=1,即3在队列中,就不用入队。
由于dis[4]>dis[2]+1,dis[4]=dis[2]+1,由于vis[4]=1,即4在队列中,就不用入队。
4. 将队列中的头元素3取出,并将vis[3]=0,遍历3的子节点(4)。
由于dis[4]<dis[3]+3,不用更新。
5. 将队列中的头元素4取出,并将vis[4]=0,由于4没有子节点,不进行遍历,此时队列为空,结束循环,dis[i]即为1到i的最短路
再此贴上本题代码
#include<bits/stdc++.h>
const long long inf=2147483647;
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,cnt=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
int next,v,w;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int u,int v,int w) //邻接表建图
{ edge[++cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
void spfa()
{
queue<int> q;
for(int i=1; i<=n; i++)
{
dis[i]=inf; //带权图初始化
vis[i]=0; //记录点i是否在队列中,
}
q.push(s); dis[s]=0; vis[s]=1; //起点入队,进行标记
while(!q.empty())
{
int u=q.front(); //取出队首
q.pop(); vis[u]=0; //出队标记
for(int i=head[u]; i; i=edge[i].next)
{
int v=edge[i].v;
if(dis[v]>dis[u]+edge[i].w) //如果有最短路就更新
{
dis[v]=dis[u]+edge[i].w;
if(vis[v]==0) //未入队则入队
{
vis[v]=1; //标记入队
q.push(v);
}
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1,u,v,w; i<=m; i++)
{
cin>>u>>v>>w;
addedge(u,w,w);
}
spfa();
for(int i=1; i<=n; i++)
if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
else cout<<dis[i]<<" "; //否则打印最短距离
return 0;
}
题目练习:
https://www.luogu.com.cn/problem/P1073
https://www.luogu.com.cn/problem/P1342