一组顶点Vi(i=1~n),顶点间通路(Vi, Vj), 通路的距离dis(i,j)。
目标:
任意给定一组起点s, 终点d, 计算s==》d之间的最短距离, 并给出通路。
算法输入数据举例如下:
4 //四个顶点
4 //四个通路
1 2 4 //顶点1到顶点2存在距离为4的通路
1 3 5 //…
2 4 3 //…
3 4 1 //顶点3到顶点4存在距离为1的通路
1 4 //求顶点1到顶点4的最短距离
Dijkstra算法可能的思路:
1.设s==》d之间的最短距离为dis_min(s,d),设在s==》d之间可以找到k(k一般为无穷大)条通路,每条通路距离为dis_m(s,d) m=1~k,显然dis_min(s,d) = min{dis_m(s,d) m=1~k}。如果,我们选定了一条s==》d之间的通路,我们如何确定它就是最短的呢?这个不好论证,因此我们需要换一种方法来论证:扩大dis_min(s,d)的比较范围和论证范围。
2.设s==》n个点之间的无穷个路径的无穷个距离排序后为0~dis_max,显然0是s==》s的最短距离,那么哪一个是s==》d之间的最短距离呢?或者说:哪一个是s==》任意点之间的最短距离呢?
3.我们从0~dis_max中间挨个选取,首先0被选出(因为是s==》s的最短距离),而后dis_1被选出(因为是s到它附近最近一个点的距离,例如:s周边有j个点与s直接相连,这样就有j个距离,显然在j个距离中必然存在一个最小值dis_x,dis_x不可能被突破,有dis_1== dis_x),而后是dis_2被选出?似乎难以判断。但从dis_1的选出可以看到一种不完整的选择规则:我们可以很容易地选出与s最近的点,但是如何选出与s第二近的点?
4.想想第二步中dis_0 = 0被选出的过程,以及dis_1被选出的过程,实际上,找到下一个点的方法已经出来了:将dis_1连接的点(设为s_1)加入到源点s集合中,考察与s、s_1直接连接的所有点,计算它们与s的距离,选择最短的路径对应的点s_2加入源点集。这样我们就选出了与s最近的三个点,继续查找下去就会获得s到d的最短路径。
另注:
一个逆向结论:设s==》s_1==》s_2==》s_3==》…==》s_n==》d是s==》d的最近路径,那么s==》s_1==》s_2==》s_3==》…==》s_n一定是s==》s_n的最近路径,否则就可以用s==》s_n的最近路径来替换s==》d的那段路径,这样就与假设不符了。但是反过来,由s==》s_n是最近路径推论s==》s_n==》d是最短路径是不行的,因为可能存在s==》s_n==》s_a==》d更近。
以上逆向结论对应的顺向推导结论只能这样:找到所有源点集的直接相连点(不能在源点集中找,因为这样会形成无效环路),计算这些通路的距离,将最短的通路所关联的点加入到源点集。
数据结构:
1.点
2.两点间联通路径及其方向、距离
3.close表、源点集(源路径集。每个源点记载到s点的距离及路径)
4.open表、等待比较的路径集(以路径长度排序)
算法:
从点集中将s点移入close表。
while(close表中没有找到d点)
{
将close表中最近加入的源点的新路径加入open表。
从open表将最短的一条移入close表。从open表中删除尾段为对应新源点的其它路径。
}
这个Dijkstra算法,我看过数遍,但至今仍然觉得我没有真正理解它的精髓所在。上次得力于一位朋友给我讲解了一下基本Dijkstra算法及其变化版本,感触最深的是其优雅的适应算法的数据结构。数据结构依赖于算法的确立,算法依赖于源数据和目标的确立,同时数据结构和算法两者又相辅相成。这次花时间用自己的一种方法从特殊的角度描述Dijkstra算法,试图将Dijkstra算法叙说的比较触及根源,但自我感觉还是不够,或许还是我的数学底子太差,描述问题不够清晰条理。