寻找最短路径

这方面的经典算法,有Dijkstra算法和Floyd算法。

下面简单说一下基于Dijkstra算法略作小改动的一个算法。

假定,问题是这样的:

我有N个点,每个点都与如果个别的点相连,是一个有向连接,且连接上有权重w_{i,j},可以为负。接着,我们要求每个节点i最多只能经过p_i次。
现在,给定起点和终点,求一条连接,其上的总权值最小。

算法的思路很简单:

  1. 构造一个数组类型的数据结构,每个元素是从起点到当前位置的所有经过的节点,称为路径。
  2. 构造一个集合,将所有路径的权重值和路径两段可以经过的次数的最小值成对放入并升序排列,如果多条路径的权重值相同则将各自两段节点的可经过次数的最小值累加起来。
  3. 构造一个目前所有走过的路径的集合。
  4. 对所有路径集合排序,找出权值最小的路径,并将其从所有路径集合中移除。
  5. 选择上述最小权值路径的最后一个节点,找出该节点的所有邻点。
  6. 判断该节点是否是终点,如果是终点,则将当前所有路径集中的最小权重路径的权重加上2中集合的所有负权值乘次数的总和,判断是否比该路径的权值小,如果更小,则将该路径和备选最优路径比较,将权值更小的选为新的备选最优路径;否则,则和当前备选最后路径比较,将权值更小的作为最优路径输出,结束循环。
  7. 查看上述邻点,检查其在当前路径中出现的次数是否超过对应的最大经过次数,如果没有超过,则复制当前路径,并将该邻点添加到最后,以当前路径的权重值加上当前节点到该邻点的连接的权重为新路径的权重。
  8. 在2的集合中寻找当前路径的权重对应的元素,将该元素中的总次数减一,如果减到0则从2中的集合中移除该权重对应的元素。
  9. 判断上述邻点是否为终点,如果不是终点则跳到X。
  10. 将上述过程中新生成的所有没有到达终点的新路径加到所有路径集合中。
  11. 重复4。

从某种角度来说,这是一种深度优先搜索算法。

这样的策略下,即便权重是负值,因为次优选择如果加上所有可以加的负权重后依然不比当下最小权重更小,那么当下最小权重自然就是最终最小权重了。

这个算符当然还不是最优的,至少在某些情况下存在进一步优化的可能。

比如,假如每个节点都只允许通过一次,那么上面的策略就可以调整为,记录每个节点是否已经被通过,所有路径共享这一信息,而不是在每条路径内自己做比较,这样在搜索的时候可以优化很多,将搜索空间压缩掉很多。

而如果权值不能为负数,那么备选最优的部分也可以跳过,因为次小权值加上一个非零实数,怎么都不会变成最小权重的。

事实上,还有一种大致可以将计算量减少一半的方案,就是从起点和终点同时开始以上述方法向外探索(注意对于有向图来说,从终点开始的权值的取值方向和搜索方向是反向的),直到两个搜索区域接触,然后走一下备选最优路径的选择过程,直到没有更优为止。

这套算法本身可以看做是一个不断作圆向外推广的过程,所以最开始的只从起点开始搜索的方案,需要走过的路径如果看做一个圆的话,那么当我们从起点和终点同时开始搜索的时候,就是两个等大的圆相切。前者的搜索空间正比于r2,r为起点和终点的距离,而后者的搜索空间只要(r2)/2。

当然,实际的问题中当然不是圆,所以这只是一个大致的类比。

总之,双源头的搜索是更优的方案,而如果问题本身有一定的限制,比如每个节点只能通过一次或者没有负权重,那么就可以有更加高效的方案。

上面谈了下经典的寻找最短路径的算法。

这里再深入一下。

我们就假定每个节点只能通过一次,且每条边的权重都大于零。

那么,一个N个节点构成的网,那么上述算法的计算量大约就是O(k N^2)的量级,其中k是平均邻点数。

显然,如果不用高级算法的话,这个极限是很难突破的了。

那么,如果我们用一些高级算法,比如蚁群算法、退火算法和遗传算法呢?

以1000个节点的TSP问题为例,在1000个节点中选择一条闭合路径链接所有节点,且要求这条路径最短。

通常的算法,基本就是上面所说,计算量在O(N^3)的量级(这里没有明确的邻点概念,所以k = N)。

然后,使用蚁群算法、退火算法和遗传算法后,有趣的情况出现了:

恰当配置下,蚁群算法最优,遗传算法结果最差。

但蚁群算法收敛慢,且容易陷入局部极有陷阱,这方面遗传算法好。

然后,我们做一个优化:将遗传算法得到的结果,和蚁群算法一样做权值统计,此后的变异不是完全随机的变异,而是以权值统计出的权重作为几率的基础,来做变异。

这样的结果就好了很多。

再进一步,和退火算法一样,我们引入系统温度,基因池分为两部分,一部分是按照每个基因的适应度作为几率做筛选留下的“优质”基因,一部分是随机抽选留下的基因,可能优也可能差。这两部分基因根据一定的比例混合,而这个比例是温度的函数,温度则有算法给出的结果来控制。

这么三种算法混合后,我们很惊讶地发现,混合算法明显可以找到更加优的结果,但缺点也很显然:太慢了——当然,还是比O(N^3)要好的。

从这里我们也可以看出一些好玩的东西来:

演化是一种很尴尬的存在,首先它不能坚定地沿着当下最优的方向走,这样可能会走入局部极优陷阱而走不出来;另一方面,又不能都是随机行走,这样的结果太糟糕。只有两者的恰当结合,才能有更好的发展。

本文遵守创作共享CC BY-NC-SA 4.0协议

通过本协议,您可以分享并修改本文内容,只要你遵守以下授权条款规定:姓名标示非商业性相同方式分享
具体内容请查阅上述协议声明。

本文禁止一切纸媒,即印刷于纸张之上的一切组织,包括但不限于转载、摘编的任何应用和衍生。网络平台如需转载必须与本人联系确认。

如果喜欢简书,想要下载简书App的话,轻戳这里~~
<small>私人推荐订阅专题:《有意思的文章》《严肃码匠圈》</small>

    原文作者:Bellman-Ford
    原文地址: https://www.jianshu.com/p/e77b05d7ec50
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞