单源最短路径之Bellman-Ford

Bellman-Ford的使用范围

1、单源

2、有负权重

3、有向

Bellman-Ford算法的描述

最短路径估计值g(v):当前求得的源节点s到节点v最短距离

最短路径d(v):源节点s带节点v的最短路径距离

Bellman-Ford算法通过对所有的边进行松弛操作来渐渐地降低从源节点s到每个节点v的最短路径估计值g(v),直到g(v)=d(v)。

Bellman-Ford算法的模板

	class Edge//表示边,u为边的起点,v为边的终点,w为边的权重
	{
		int u;
		int v;
		int w;
	}
	
	int n;//节点的总个数
	int m;//边的总条数
	int s;//源节点
	Edge e[];//e[i]:第i条边
	int d[];//d[i]:s到i的最短路径长度
	boolean bellman_ford()
	{
		d[s]=0;
		boolean flag=false;
		//*//对所有的边进行n-1次松弛
		for(int i=1;i<n;i++)
		{
			flag=false;
			//**//对所有的边进行松弛
			for(int j=0;j<m;j++)
			{
				int u=e[j].u;
				int v=e[j].v;
				int w=e[j].w;
				if(d[v]>d[u]+w)
				{
					d[v]=d[u]+w;
					flag=true;
				}
			}
			if(!flag)//若flag为false说明本次没有对任何一条边进行松弛,那么以后的每一次都不会对任何一条边进行松弛,所以剩下的松弛操作也没必要了
			{
				break;
			}
		}
		//**//
		
		//***//判断是否有负环
		for(int i=0;i<m;i++)
		{ 
			int u=e[i].u;
			int v=e[i].v;
			int w=e[i].w;
			if(d[v]>d[u]+w)
			{
				return false;//有负环
			}
		}
		return true;//没有负环
		//***//
	}

收敛性质:对于某些节点u,v,如果s~u~v是一条最短路径,并且在对边(u,v)进行松弛前的任意时间有g[u]=d[u],则在之后的所有时间有g[v]=d[v]。

证明Bellman-Ford的正确性

1、证明若不存在负环,则对所有边进行n-1次松弛之后,对于所有从s可以到达的节点v,有g[v]=d[v]

证明:设p=(s,v1,v2,…,vk)为从源节点到vk之间的任意一条最短路径。根据收敛性质,在进行第一次松弛后,g[v1]=d[v1],在进行第二次松弛后,g[v2]=d[v2],。。。,在进行第k次松弛后,g[vk]=d[vk]。由于p最多包含n-1条边,所以经过n-1次松弛后,对于所有从s可以到达的节点v,有g[v]=d[v]。

2、证明对所有边进行n-1次松弛之后,若有某条边(u,v),使得g(v)>g(u)+w(u,v),则存在负环

证明:我们可以断言:若没有负环,则对于任意一条边(u,v),有g(v)<=g(u)+w(u,v)。由于该命题成立,则该命题的逆否命题也成立。

所以可以推出:若有某条边使得g(v)>g(u)+w(u,v),则存在负环。得证

3、证明对所有边进行n-1次松弛之后,若对任意的边(u,v),都有g(v)<=g(u)+w(u,v),则不存在负环

证明:假设存在负环,设该环路为c=(v0,v1,v2,…,vk),v0=vk。

由于c未负环,所以有w(v0,v1)+w(v1,v2)+…+w(vk-1,vk)<0。

由于对于所有的边都有g(v)<=g(u)+w(u,v),

所以有g(vi)<=g(vi-1)+w(vi-1,vi),i=1,2,…,k,

将k个等式加起来,有g(v1)+g(v2)+…+g(vk)<=g(v0)+g(v1)+…+g(vk-1)+w(v0,v1)+w(v1,v2)+…+w(vk-1,vk),

由于v0=vk,

所以有g(v0)=g(vk)

所以有w(v0,v1)+w(v1,v2)+…+w(vk-1,vk)>=0.

这与w(v0,v1)+w(v1,v2)+…+w(vk-1,vk)<0相矛盾。所以命题正确

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