解决问题的范围:存在负边权的最短路问题
时间复杂度:O(km) m是边的条数k是常数,算法是效率还算是比较高的,这个算法的时间复杂度的最坏是O(n*m)因此当没有负权的时候还是用dijkstra吧
它和dijkstra 的不同点在于spfa 的标记数组是标记是否还在队列中(注意这个)
算法的过程:
加入初始的点,一般都是1,放入队列中,取队列的队首元素,遍历与队首元素相邻的点,如果距离变短则更新这个最短的值,如果这个点不在队列中就加入队列,如果在队列中就不用处理
代码中由注释:
给出一个模板题:
https://ac.nowcoder.com/acm/problem/14369
code:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+10;
int head[N],w[N],e[N],ne[N];
int dis[N],st[N];//dis 记录每个点到1最短距离 st记录每个点是否在队列中
int n,m,cnt;
void add(int u,int v,int val){//链式前向星加边
e[cnt]=v,w[cnt]=val,ne[cnt]=head[u],head[u]=cnt++;
}
void spfa()
{
memset(dis,INF,sizeof(dis));
queue<int> q;
q.push(1);
dis[1]=0;
st[1]=1;
while(q.size()){
int t=q.front();
q.pop();
st[t]=0;//出队置为0
for(int i=head[t];i!=-1;i=ne[i]){
int v=e[i];
if(dis[v]>dis[t]+w[i]){//更新最短的路径长度,如果该点在队列中就不用操作,不在队列需要加队列中
dis[v]=dis[t]+w[i];
if(!st[v]){
st[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>m;
int u,v,val;
while(m--){
cin>>u>>v>>val;
add(u,v,val);
}
spfa();
for(int i=2;i<=n;i++){
cout<<dis[i]<<endl;
}
return 0;
}