最短路径问题:如果从图中某一顶点(称为源点)到达另一顶点(称为终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边上的权值总和达到最小。当然这只是最基础的应用,关于单源最短路径还有很多变体:
1.单源最短路径
2.单目的地最短路径
3.单节点对最短路径
4.所有节点对最短路径
最短路径定义:
路径p=<v0, v1, … vk>的权是指组成p的所有边的权值之和
从u到v的最短路径的权为
从u到v的最短路径是权的任何路径
节点V的前驱节点表示为:Vπ
需要说明的是这里讨论的单源最短路径允许出现负数权值,但是不能图中不能出现权值为负数的环路,因为一旦图中出现了权值为负数的环路那么图中有些节点是不可能有最路径的。例如:图中节点0到节点1权值为1,节点1到节点0权值为-2,那么第一轮从0->1的最短路径为1,但是在节点1的时候发现1->0可以更小也就是-2,下一轮-2+1<1那么节点1的权值被更新为-1,如此循环下去会变成负无穷大。
常用的单源最短路径的解法有两种:Dijkstra算法和bellman_ford算法。
松弛操作
松弛:先测试v到s之间的最短路径是否可以改善,可以则改善。可能很多人会有疑问为什么突然讲了一个松弛操作?这是因为单源最短路径和所有节点对的最短路径都是基于松弛操作来实现的,只不过不同的算法采用了不同的松弛次数和顺序。
例如下图所示,S-->B的直接距离为8,但是检测S-->A-->B的距离为5;5<8因此进行一次松弛,得到S-->B的距离为5
实现伪代码:
w(u,v)表示边u-->v的权值,u.d和v.d分别表示点u和v到源点s的距离
relax(u,v,w){
if v.d>u.d+w(u,v)
v.d=u.d+w(u,v)
v.π=v
}
if v.d>u.d+w(u,v)
v.d=u.d+w(u,v)
v.π=v
}
bellman_ford算法
bellman_ford算法可以解决带有负权值的图的单源最短路径,如果图中包含了一个权值为负的环路,则该算法返回false,否则返回true;
初始化
初始化很好理解,就是将图G中的所有节点到源结点s的距离设置为