SPFA算法:
主要是为了求解图中的单源最短路径(可以含负权边),是对Bellman-Ford 的优化,但无法完全取代Bellman-Ford。SPFA算法可以解决,Dijkstra算法无法解决的权值为负的情况。
为什么出现负权值dijkstra算法失效
我们看张图,从1号结点开始执行dijkstra算法,我们在权值6和5的边中选择权值为5的边此时来到二号结点d[2]=5,然后选择边权为-2的边更新d[3]=3,结束dijkstra算法。我们可以看到结束时d[2]=5,而实际上d[2]应该=4才是最短路径,也就是从1–>3–>2这样走才是最短的。这是因为dijkstra算法实际上是贪心算法,所以导致了错误的发生!
SPFA算法实现过程
我们用一个队列,每次拿去队首元素,先取消标记表示已经出队,然后遍历与队首元素相关的边,更新他们的d[v],如果结点不在队中,那么将该结点入队,并标记!依此类推,每次拿出队首,取消标记,更新d[v],若不在队中就标记入队,直到队列为空我们就可以得出起始点到所有点的最短路径。
如何判断是否更新d[v]?
我们用当前结点u的d[u]+此边边权判断是否小于原来的d[v],如果小于更新d[v],在判断是否在队中,如果在不入队,不在则入队!
顺序问题
先判断是否更新d[v]–>如果更新d[v]–>判断是否在队列–>不在入队!
(不管v点在不在队列,只要d[v]>d[u]+此边边权就更新)
实现代码:
void spfa(int start)
{
d[start]=0;
vis[start]=1;//标记入队
queue<int> q;
q.push(start);
while(!q.empty())
{
int t=q.front();
q.pop();
vis[t]=0;//出队取消标记
//遍历与u点相邻结点
for(int i=0;i<M[t].size();i++)
{
edge e=M[t][i];
if<