Yen 算法

 1.2. Yen 算法

http://imlazy.ycool.com/post.1956603.html

    我从《The K shortest paths problem》这篇文章中学到了另一个算法,名叫 Yen 算法(Yen 是发明者的名字)。它和上面讲的典型的 A* 算法使用相同的启发函数,但是状态的含义以及扩展状态的方式不同。

    在 Yen 算法中,状态 x 不仅可以代表从 s 走到 x.v 的一条路径(记作 Psv),更代表了一条从 s 到 t 的完整的路径,也就是 Psv 再连接上 从 x.v 到 t 的最短路径。这一整条路径(记作 Px)的长度就是我们的启发函数 f(x)。

    在每个状态 x 中,还需要保存 x.v 在 Psv 中的前一个点,我们记作 x.pre。边 x.pre -> x.v 就称作 Px偏离边deviation edge); Px 上从 x.pre 到 t 的这一段子路径就称为 Px偏离路径deviation path)。为什么叫作偏离路径,看到后面都明白了。

    先求出从 s 到 t 的最短路径,它就是初始状态 x1 所要代表的路径。设它的第一条边是 s -> a,则  x1.v = a; x1.len = w(s, a) (w(s, a) 表示边 s -> a 的长度);  x1.pre = s,也就是说,规定 Px1 的偏离边是 s -> a。

    把 x1 放进优先队列。接下来,每当进入最大的循环的第 i 轮,从优先队列里出队的状态(启发值最小的,也就是路径长度目前最短的状态,记作 xi)就代表了第 i 短的解。第一轮出队的当然是前面定义的初始状态 x1。下面要从它发展新的状态,作为可能的第 2 短的解,放进优先队列。发展的方法如下:

    对于 Px1 的偏离路径上的每一条边(设它为 u -> v),都要找出另一条边 u -> v',满足在所有从点 u 出发的边当中, w(u, v') + dt(v') 仅仅高于 w(u, v) + dt(v) (或与它相同);也就是说,从 u 出发,走 u -> v 这条边到终点是最近的,走 u -> v' 这条边是第 2 近的(或者一样近)。从每一条 u -> v',我们都可以发展出一个新状态 x': x'.v = v'; x'.len = w(Psu) + w(u, v'); x'.pre = u,也就是说 Px' 的偏离边就是 u -> v'。

 



图 1

 

    图 1 给出了一个例子。假设图中蓝色和黑色的边组成的路径就是 P x1,蓝色边是它的偏离路径;那些红色的边就是前面说的那些 u -> v';红色的虚线就代表了从每个 v' 到 t 的最短路径。可见,每条 P x' 都是从 u -> v' 开始从 P x1 “身上” 偏离出来的,因此把 从偏离边到终点 的这一段路径称为 P x'偏离路径

    注意,由于本问题中求的路径是 可以带环的,所以走到终点以后还可以回头再走。因此,在图 1 中可以看到在点 t 后面也发展了一条偏离路径。这条偏离路径显然不再需要是第 2 短的,而是从 t 出发再回到 t 的最短的路径。

    上面讲的是从 x 1 发展状态的情况。从之后的 x i 发展状态的时候还有一点要注意:在我们寻找偏离边 u -> v' 的时候,如果 u == x i.pre (也就是当 要找的偏离边 和 x i 的偏离边 是从同一点出发时),则要注意 u -> v' 不仅要和 u -> x i.v 不同,而且要和 x i 的所有祖先状态中从点 u 出发的那条边都不同,不然新发展的状态岂不是和 x i 的祖先状态重复了。



图 2

 

    图 2 给出了一个例子。假设蓝色路径是从黑色路径中发展出的偏离路径;当从蓝色路径发展偏离路径时,要找的是除了蓝色和黑色的边以外,能以最短的距离走到 t 的那条边,假设这里我们找到的是红色的那条边;当从红色路径发展偏离路径时,要找的是除了红色、蓝色和黑色的边以外,能以最短的距离走到 t 的那条边,假设这里我们找到的是绿色的那条边。

    如此一来,可能有很多偏离路径都是从同一点偏离出来的,但是它们的偏离边都不相同。要在程序中实现这一点,可以在每个状态中记录下所有祖先状态的偏离边。

    显然 Yen 算法也是一个 A* 算法,但是它有一个特点,前面已经说过了,就是最大的那个循环最多只要做 K 次,因为每当一个状态出队列时,我们就找到了一个解。因此基本上可以估计出算法的时间复杂度:

  • 设图中有 N 个点,那么一条偏离路径上最多只有 N 条边(因为它是一条边 加上 从某一点到终点的最短路径),也就是说,从一个状态最多发展出 N + 1 个新状态(偏离路径上的每条边发展出一个,从点 t 再发展出一个)。
  • 寻找一条偏离路径时,需要扫描从一个点出发的所有边,暂且假设从一个点出发的边最多也是 N 条,那么这一步要花 O(N) 的时间。
  • 可以想象优先队列(Open 表)里最多有 O(K * N) 个元素,所以每次维护优先队列的时间差不多是 O( lg (K * N) )。

    因此,总的时间复杂度,在最差情况下,差不多就是 O( K * ( N2 + lg(K * N) ) )。当然这只是我个人估计一下,不要太拿它当回事。

    1.3. MPS 算法

    同样是在《The K shortest paths problem》这篇文章中,还介绍了作者自已发明的 MPS 算法(MPS 是该文章的三位作者的名字缩写)。它的框架和 Yen 算法相同,但是有一个优化,可以加快寻找偏离边的速度。方法就是把从每个点出发的所有边,都按照从该条边走向 t 的最短距离 升序排序(最好用邻接链表描述图)。



图 3
    图 3 给出了一个例子。图中从点 s 出发的边有红、蓝和绿三条,延着它们到达终点 t 的最短距离分别为 3、 2 和 4。因此把从 s 出发的边排序为 (蓝, 红, 绿)。

    这样一来,寻找偏离边的时间就只有 O(1) 了。因为我们从某一点第一次发展偏离边时,只要选它的邻接链表中的第一条边;下一次再从该点发展时,只要选第二条边……再也不用一一扫描所有边了,也不用担心会和祖先状态的偏离边重复了。

    假设图中有 N 个点,从每个点出发的边最多也是 N 条。那么排序一个点的邻接链表需要 O(N * lg N) 的时间,排序整个邻接链表的时间就是 O(N 2 * lgN);搜索的时间由 Yen 算法的 O(K * N 2) 降至 O(K * N)。因此,整个算法在最差情况下的时间复杂度大约就是 O(N 2 * lgN + K * N)。(从数字上看,好像也没有比 Yen 算法快到哪去 ……但是实际试下来确实是快的。)

Yen算法和MPS算法是两种用于求解K最短路径问题的算法。它们的目标是在给定的图中找出K条最短路径。 Yen算法是一种改进的A*算法,它的核心思想是通过不断地从当前最短路径中删除一条边,然后再计算从起点到终点的最短路径,以此来寻找更短的路径。具体来说,Yen算法使用了一个优先队列来维护当前的最短路径,每次从队列中取出最短路径并计算其偏离路径,直到找到K条最短路径或者队列为空。Yen算法的时间复杂度在最坏情况下约为O(K * N^2 * lg(K * N))。 MPS算法是在Yen算法的基础上进行了优化。它使用了一种排序的策略来加快寻找偏离边的速度。具体来说,MPS算法将从每个点出发的所有边按照从该条边走向终点的最短距离进行升序排序,这样一来,寻找偏离边的时间就只有O(1)了。MPS算法的时间复杂度在最坏情况下约为O(N^2 * lgN + K * N)。 综上所述,Yen算法和MPS算法都是用于求解K最短路径问题的算法,它们的时间复杂度都与图的规模N和需要找到的最短路径数K有关。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Yen 算法](https://blog.csdn.net/KZM2008/article/details/5460152)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值