spfa算法:最短路径算法,适用于求解带有负权的图的最短路径,是BellmanFord的一种优化
时间复杂度:O(kE),k为每个节点进入队列的次数,一般<=2,最坏情况下为O(VE)
局限性:适用于稀疏图,同时不能输出负环(仅能检测负环,如果需要输出负环可使用BellmanFord算法),算法不稳定
本质:宽度优先搜索+剪枝(将一个节点压入队列之前需要先判断这个节点是否已经在队列中)
代码:
int head[MAXN],tol;
struct Edge{
int v,cost,next;
}edge[MAXE];
void addEdge(int u,int v,int cost){
edge[tol].v=v;edge[tol].cost=cost;edge[tol].next=head[u];head[u]=tol++;
edge[tol].v=u;edge[tol].cost=cost;edge[tol].next=head[v];head[v]=tol++;
}
bool vis[MAXN];///在队列标志
int cnt[MAXN];///每个点的入队次数
int dis[MAXN];///如果想要打印路径可以声明一个pre[]记录前驱即可
bool spfa(int s,int n){
mem(vis,false);
for(int i=1;i<=n;++i) dis[i]=INF;
vis[s]=true;
dis[s]=0;
queue<int> q;
while(!q.empty()) q.pop();
q.push(s);
mem(cnt,0);
cnt[s]=1;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=false;
for(int k=head[u];k!=-1;k=edge[k].next){
int v=edge[k].v;
if(dis[v]>dis[u]+edge[k].cost){
dis[v]=dis[u]+edge[k].cost;
if(!vis[v]){
vis[v]=true;
q.push(v);
if(++cnt[v]>n) return false;///判断是否存在环
}
}
}
}
return true;
}