标题今天来谈一谈狄克斯特拉算法,看到网上的讲解就是给一个带权无环图,然后就开始一顿操作猛如虎,同学们看的津津乐道,但发现自己还是二百五。原因还是理解的不够透彻,或者说只清楚操作流程而不明白操作原理,凭什么这样就是对的。
首先DJ算法是解决求解一个带权图的最短路径问题的,比如我们要求图中A点到B点的最短路径,DJ是可以做到的,但为什么理解起来就那么困难呢。其实DJ做的事情不止你的需求,远远高于了你的需求。DJ不仅求出了A到B最短距离,实际上求出了以A为出发点到图中其余点的所有最短路径。这也就是问什么DJ的操作这么复杂。为什么要说这些呢,就是希望小伙伴们能够理解DJ为什么会出现大量的无关你的问题的操作,与其说他是一种解法,不如说是一种想法,是一个体系,在这个思路流程下,以图中任意点x为起点,可通杀其到任何其他点的最短路径。DJ确实也做到了。
下面我们来真正的开始理解DJ之旅吧,我力求从最优解迭代的角度去解释DJ的操作。而不是让你被动接受这个既定的操作,而是主动的理解他的精妙。
在理性探讨之前,我希望大家有这样一个认识(很重要),那就是:你要去完成一件任务,我们叫他mission,那么你搞定你的mission无外乎两种方式,1.直接硬刚搞定 2. 迂回搞定,我想去搞定一个中间的事,再以这个事为跳板去搞定我的mission。 恩,如果承认的话,那么恭喜你你离DJ又近了一步。有人要问,说这些干什么,我要说这两个东西,渗透在了DJ的每一步更新的操作中,实际上你在网上看到的那些理解DJ的教程不都是在强调更新取最小吗,你确实照着做了,也确实对了,然而你也确实啥也没懂。因为作者不会告诉你这些是为什么。而我刚才说的这个事就是引导你慢慢知道为什么这么做。我可以先告诉你DJ的更新本质就是在对于你要达到的目标是直接去还是迂回去的按照最短来取舍。这个直接是广义的,表示当前的已经存在的到达目标点的路径,而迂回则是不适用已经存在的,接着绕。(比如从已知A到B距离是10,A到C距离是6,那么明明有A到B的距离为10 的通路我暂且不选择,万一一会儿发现C到B距离是2,那我A—>C—>B就是8,大概就是这个意思)
当你同意解决一个事情的确就这两种情况,并基于你对DJ的印象感觉我加粗的话有点意思的时候,我们继续:
那么你要明白靠近DJ的第二个道理:那就是如果你走着去学校是10分钟(直接),而你要花15分钟叫醒你的妈咪,然后她用3分钟开车送你去学校的时候(迂回)。你应该清楚你该怎么做。
抽象提取一下:就是当前的你可以解决mission的路径(例子里的时间),比任何其他你打算用来迂回解决的备选路径都短的时候,就别怀疑了,当前的就是最短的,因为别的还没到达mission呢,就已经比到达的长了,那你还迂回个什么劲呢?对吧!!! 有没有什么感觉,我说的不正是DJ更新候选集的准则吗。是不是感觉心情暖暖的~
好了 如果你坚持读到这了 恭喜你DJ的精髓你已经初步领略了,然我带着你实际操作一下。

开始DJ之旅:
假设今天我们从A出发,那么对于A来说,和A直接相邻的就只有B,C。
故我们的状态S:A—>B: 6
A—>C: 3
A—>rest :NULL
在很多地方A到其余记做正无穷,我觉得其实是为了迎合集合筛选取最小时候的数学处理。从状态角度来说,其实就是对于A—>rest一无所知,故我用NULL表示,当然不参与到筛选中,因为一无所知就不能参与比较。
那么到这可以得到什么结论呢?如果你深刻理解了我们预热阶段的两个道理,我们可以说A—>C为A到C的最短路径。因为另一个和A直接相邻的就是B了,而A到B距离为6,也就是说对于A到C这个事情,若采用A到X再到C迂回方式,那么无论如何这个方式的距离开销必定大于6,所以迂回在这是不讨好的,故一定有A,C之间最短路径 :A—>C:3 。 其实由图论的知识,也可知任意x∈rest,有A—>x > A—>C 。故A—>C 是当前状态集最小的。
那么状态S是否就变为了:A—>B: 6 A—>rest :NULL呢?然后同学就想是不是接下来就该把A—>B拿出来了当做最短路径了!!哈哈,那你的思维就还不严谨了一点点。我承认对于当前rest中的任意x,A—>x > A—>B,但你要想想当前的状态集完备吗?是否还有路径信息没有罗列出来呢?如果对于从点A到点B这件事,迂回完成的路径没有全部罗列出来的话,你又凭什么说 A—>B:6 就是A到B的最短路径了呢?
让我们理性分析一波:对于A到B这件事,A—>B就是直接路径。而任意x∈rest,A—>x—>…—>B都属于迂回路径。But!!当前rest里面存储的都是和A不相邻的点,所以C不在其中,所以漏掉的恰恰是A—>C的衍生迂回路径啊!! 而此例中正是A—>C的衍生路径A—>C—>B逆袭了A—>B!!!所以正确更新后的状态集S应该是:
**
A—>C—>B: 3+2 =5 replace A—>B : 6 !! 王朝更替
A—>C—>D: 3+3 =6
A—>C—>E: 3+ 4 =7
A—>rest(已经更新,D,E已经有了) :NULL (此时的rest已经不是彼时的rest了,彼时的rest里含有D,E,此时的rest里已经没有了,因为已经由A—>C衍生出了D,E信息)**
所以你自然的发现了原来A到B还真有比直接去更短的路勒!!!开心ing。故A到B的最短路径是 A—>C—>B: 3+2 =5。有同学会说rest是否暗藏到B的最短的路径呢,首先根据rest的定义,当前rest的点都是和A,C不相邻的,所以即便有通过rest里的点x到达B的路径,其形式必为 A—>C—>(B,D,E)—>x—>…—>B,故可证A—>C—>B: 3+2 =5 为当前状态集的最小值,且A—>C—>B一定是A到B的最短路径!!
至此 我们求得A到B的最短路径: A—>C—>B: 3+2 =5
那么状态集再次更新,当然是剔除掉 A—>C—>B: 3+2 =5 ,然后呢,A—>C—>D: 3+3 =6成为了可见的最小,但是要警惕谁的逆袭?如果你明白了的话,没错正是要警惕 A—>C—>B的衍生路径的逆袭喽,所以筛选之前加入 A—>C—>B的衍生路径状态集才完备哟!然后一直将爱情进行下去直到状态集为空,则由A出发到所有点的最短路径就都求出来了。(离婚!)
## 标题 总结:DJ的策略## 标题
实际上由一个源点出发:
1.完备当前状态集(即把当前所有的信息罗列出来)
2.提取基于我们在开篇就提到的那个优化逻辑筛选最短路径
3.返回1,更新并且完备状态集,这一点保证了每次从状态集筛选出来的路径一定是到达这个点的最短路径
所以DJ的精髓正是每次筛选后对状态集的更新和完备性的维护。而我们筛选正是水到渠成的事情,你理解了前面直接去学校还是叫醒妈咪开车送你去的道理,筛选的操作就自然领会了。
感悟:这篇博文我保证和网上的任何一篇都大不相同,因为我并不是在介绍流程而是在解释流程,在你顺着我的讲解完成了流程的演算的时候,你其实也就明白的差不多了。算法上脑筋的不是流程,而是流程凭什么张这个样子,有时候学习真是一件辛苦的事。
1万+

被折叠的 条评论
为什么被折叠?



