前言:
Dijkstra算法算是比较经典的一个求单源最短路径的一个算法了,有向图和无向图都可以使用,对于采用邻接表还是邻接矩阵存储图也没有要求。
我在一开始学习这个算法的时候,虽然知道算法的具体处理流程,但是对于算法的原理却是一知半解,在做PTA一些算法题的时候遇到了稍微灵活的题目就歇菜了。所以翻看了一写文档,自己归纳整理了一下原理,也有一些自己的想法,如有不当之处,还望批评指正。
算法步骤
参数说明
start : 出发结点
end : 终点
S : 已确定最短路径的结点集合
算法描述
1.按题目要求建立邻接矩阵或者邻接表,将start放入S。
2.将所有结点在经过S中的结点到达start的距离放入lowcast数组(用于存放最短路径的长度)。
3.在lowcast数组中找到距离start最近且未在S中的结点Vi,将Vi收录进S,并更新和Vi有直接边相连的结点的lowcast的值(如果经过Vi离start更近,则更换lowcast为经过Vi的路径)。
4.重复步骤2,3,直到所有的的结点被收录进S。
算法过程图解
单源无向图:
第一步:
第二步:
第三步:
第4步:
第5步:
第6步:
算法可行性证明
一.数学归纳法:
假设前提:
1.有x个结点,lowcast为一个长为x的数组,lowcast的数组初始化为所有顶点经过S(已确定最短路径的结点集合,初始为∅)到达start的距离。
2.图为无向连通图。
可得lowcast有三种情况:
①没有和S中任何结点有边相连,值为inf
②start结点本身,值为0。
③与S中的编号为i结点有直接边相连,值为min{lowcast[x]+map[x][v]|x∈i}
归纳证明:
证明目标:
第n个被收录进S的结点一定已经找的了最短路径。
①当n=1时,即与start有直接边相连的结点距离start的最短路径,最短路径为与start直接相邻的边。当该结点V被收录进了S,与V直接相连的结点可以通过V到达start,所以需要更新与V有直接边相连的结点的lowcast的值。
②假设当n等于k时,所有S中的结点都已经找到了最短路径,所以当n为k+1时,寻找lowcast的最小值的节点V,该V必然与S中的结点有直接边相连(如果没有直接边,则距离start必为inf,而inf又是最小值,图一定不为连通图,与假设矛盾),因为S中的路径已经保证为最优路径,所以
L=min{distance{V->Vs}+lowcast(Vs)}(Vs为S中与V有直接边相连的结点)
就是V到start的最短路径长度,而L的计算已经在上一轮操作完成,即是lowcast的更新。
所以假设成立,证毕。
二.贪吃蛇法(个人理解):
首先需要理解S是一个确定的集合,经过S的n个节点后到达start都可以理解为经过一个S到达start。很好理解,这里我不做证明
1号结点被收录进S
2号结点被收录进了S
4号结点被收录进了S
3号结点被收录进了S
由上图图方法可得最短路径。
PTA题目:
这篇文章是我在pat上做题时遇到了一个dijkstra算法的题目,想到自己大一虽然学了这个算法,也敲了好几遍代码了,但是总的思想还是不清晰,在pta上遇到时花了很多时间才AC,所以写了一篇博客整理了一下dijkstra算法的思路。其实这个算法不难,主要是理解数归法,或者说贪心+动态规划算法的思路,其实本质都差不多。
另外我写了一个注释较全的一个关于dijkstra算法的题解,对上面理解不清晰的话可以结合题目看。