浅谈最短路之——Bellman-Ford和SPFA

       最短路算法中,精确找到最短路最常用的办法莫过于Bellman-Ford以及其优化后的SPFA算法。

    Bellman-Ford算法较Dijkstar算法可以应用于含负边权的图,对于一个图G(V,E),其中V为点集,E为边集,源点s,首先定义dis数组,dis[i]为i到s的最短距离。枚举每一条边(u,v),如果dis[u]+w[u,v]<dis[v],就更新dis[v]的值。重复这个步骤,在不存在负环的情况下最多执行N-1次,所以在寻找最短路完成后枚举所有边查看是否有dis[u]+w[u,v]<dis[v]的情况,如果有,那么就存在负环,否则dis[t]就是最短路径。

       Bellman-Ford算法实现代码:

bool bellman-ford()
{
	bool flag;
	for(int i=1;i<=n;++i)
	{
		flag=false;
		for(int j=0;j<m;++j)
		{
			int x=edge[j].from;
			int y=edge[j].to;
			int z=edge[j].w;
			if(dis[x]+z<dis[y])
			{
				dis[y]=dis[x]+z;
				flag=true;
			}
		}
		if(!flag)
		  break;
		if(i==n&&flag)
		  return false;
	}
	return true;
}

      SPFA则是Bellman-Ford算法加入队列优化后的算法,并不是每个点都需要松弛,因此也减少了不必要的计算,也就很大程度上减小了复杂度,可以证明正常情况下每个点进队次数不会超过两次。其思想是:初始时队列中只有源点s,然后用队列里的点来更新dis数组的值,设置一个vis数组来表示每个点是否被询问过,如果一个点被询问两次,那么说明图中存在负环。

SPFA求最短路代码:

bool SPFA(int st)                  返回真为存在负环,假为求最短路成功
{
	memset(dis,INF,sizeof(dis));
	vis[st]=1;
	q.push(st);
	dis[st]=0;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=nxt[i])
		{
			int v=to[i];
			if(dis[v]>dis[u]+w[i])
			{
				dis[v]=dis[u]+w[i];
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
				else
				  return true;
			}
		}
	}
	return false;
}

 

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/g21glf/article/details/81363642
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞