算法适用场景:非负权,负权非负环。
算法的实现在贝尔曼福特算法的基础上适用队列优化(类似于广度优先搜索的方法)将修改后的点放入队列后设置标记,防止下一次再利用该点进行松弛,直到改点被使用后为止。
需要用到的空间:vector领接表,队列(存放点),dis[]单源最短路径,sign[]标记是否入列过,neg[]用来判断负环(无法在负环情况下结果问题)
代码模板:
void spfa(ll s) { ll dis[10010]; bool sign[10010]; ll neg[10010]; //初始化 memset(neg,0,sizeof neg); neg[s]=1; for(ll i=1;i<=n;i++) { dis[i]=INF; sign[i]=false; } dis[s]=0; //队列操作 queue<ll> q; q.push(s); sign[s]=true; ll cnt=0; while(!q.empty()) { ll u = q.front(); q.pop(); sign[u]=false; for(ll i=0;i<e[u].size();i++) { ll v = e[u][i].v,w = e[u][i].w; if(dis[u]+w<dis[v]) { dis[v]=dis[u]+w; // pre[v]=u; if(!sign[v]) { sign[v]=true; q.push(v); neg[v]++; if(neg[v]>n)//出现负圈 return; } } } } cout<<dis[n]<<endl; //有些程序需要打印路径,这个以后再说 }
void find(int a)//利用递归找回路径 { if(a==S) { cout << S; return; } else{ find(father[a]); } cout << " " <<a; }