带有汇合节点的加权有向图的单源最短路径问题

加权有向图的单源最短路径问题是图论中的经典问题。单源最短路径问题指的是从一个节点出发,计算到图中其它所有节点的最短路径的问题。Dijkstra算法可以有效解决这个问题(权值不能为负数)。

对于加权有向图中的节点v,它的任意一个前继邻居节点u到v的路径(u,v)是一个独立的路径,不依赖任何其它前继邻居节点u'到v的路径(u',v)

我们在这里对图做一个扩展,增加一种特殊的节点,称为汇合节点。从起始节点到汇合节点的路径是汇合节点的一个或多个前继邻居节点到汇合节点的路径的组合,组合时对各个分支距离进行加法和乘法运算。

简单点讲,要想走到汇合节点,必须先同时走到它的一个或多个前继邻居节点。至于具体要走过哪几个前继邻居节点,要根据具体的条件要求来判断。

这种情况在生活中经常会遇到,一件事情有多个可选的前置条件,想要完成这件事情,必须先完成一个或多个前置条件。

以图一为例:

图一

节点d是汇合节点,这里的汇合条件是从起始节点a到d节点的路径是其所有前继相邻节点的路径的和。也就是说要想走到d,必须先同时走到b和c,然后才能计算从a到d的距离|a->d|=|a->b|+|b->d|+|a->c|+|c->d|

对于扩展后的带有汇合节点的加权有向图的单源最短路径问题应该如何解决?Dijkstra算法是否依然有效?我们来分析一下这个问题。

Dijkstra算法的原理

Dijkstra算法的特点是从起始节点开始向外层层扩展,直到所有节点都被访问到。

Dijkstra算法将节点分为两组,一个是已求出最短路径的节点的集合S(初始时只有起始节点),另一个是未确定最短路径的节点的集合U。每次新扩展一个距离最短的节点,更新与其相邻节点的距离(只在相邻节点当前的最短路径大于经过扩展节点的路径时更新)。当所有边的权值都为正时,不会存在一个距离更短的没扩展过的节点,所以这个节点的距离不会再被改变,将其加入到S中。因此,在将节点加入到S的过程中,总是保持从起始节点到S中任何节点的最短距离都不大于从起始节点到U中任何节点的最短距离。从起始节点开始,直至集合U中的所有节点都转移到了集合S中。

以图二为例:

图二

假设a为起始节点。从a出发,有b和c两个相邻节点。此时需要从|ab||ac|中选择一个距离最短的路径。如果|ac|<|ab|,因为权值为正,所以|ac|<|ab|+|bc|一定成立,因此c一定是到a的路径最短的节点,将c加入到集合S中。反之,如果|ab|>|ac|,所以b是到a的距离最短的节点,将b加入到集合S中,此时从a到c的最短路径还要通过比较|ab|+|bc||ac|的大小来决定。

汇合节点引入的问题

从Dijkstra算法的原理可以看到,节点向外扩展的过程中,每次都要从集合U中选择一个距离最短的节点。汇合节点的问题在于,在扩展节点时,无法立即计算出汇合节点的最短路径。因为汇合节点要求对它的所有前继相邻节点进行组合计算,而在扩展时难以保证汇合节点的所有前继相邻节点都已计算出最短路径。

如果不能计算出汇合节点的最短路径,那么就无法按照Dijkstra算法的要求选择出距离最短的节点。此时应该如何处理?

以图一为例,从a出发先到达c。更新c的相邻节点时,无法计算汇合节点d的距离。这种情况下应该如何处理?

对汇合节点的分析

我们首先来看节点向外扩展的过程,为什么每次都要从U集合中选择距离最短的节点?从Dijkstra算法的原理可以知道,因为需要保证不会存在距离更短的节点,从而保证被选中节点的当前路径就是从起始节点到它的最短路径,所以被选中节点可以放到集合S中。

对于图中的任意一个节点,如果它的相邻节点存在汇合节点,有两种情况:

  1. 汇合节点是路径最短的节点
  2. 非汇合节点是路径最短的节点

对于情况2,非汇合节点会被选择作为距离最短的节点,符合Dijkstra算法的要求,不存在问题。

对于情况1,我们深入分析一下。

对于非汇合节点u和它的相邻节点v,我们用λu、λv表示u和v的最短路径距离,λ|uv|表示u和v之间的距离,可以知道:

    λv=λu+λ|uv|
=>  λv>λu, λv>λ|uv|

对于汇合节点v和它的前继相邻节点u1,u2...uN,λv=C(λu1+λ|u1v|,λu2+λ|u2v|...,λuN+λ|uNv|),其中C为汇合节点v的最短路径计算函数。可以知道对于汇合节点v的任意一个位于v的最短路径中的前继相邻节点u:

    λv>=∑i(λui+λ|uiv|)(i=1~N)
=>  λv>=λu+λ|uv|
=>  λv>λu, λv>λ|uv|

对于普通节点u、u的普通相邻节点v以及u的汇合相邻节点w,如果w路径更短,则有λw<λv,假设组成w的最短路径的任意前继相邻节点为x(x可能包括u),根据上面内容可以知道:

    λw<λv
    λw>=λx+λ|xw|, λv=λu+λ|uv|
=>  λx+λ|xw|<λu+λ|uv|
=>  λx<λu+λ|uv|
=>  λx<λv

如果x=u,那么λ|uw|<λ|uv|,说明uw之间的距离小于uv之间的距离。

如果x≠u, λx<λu,则x先于u被访问,因而w先于v更新。

如果x≠u, λu<λx,则u先于x被访问,但是根据λx<λv,x会先于v被访问。

根据上面的推导,如果在节点u的相邻节点中汇合节点w的距离最短,那么组成汇合节点w的最短路径的任意前继相邻节点x都会优先于u的其它任意相邻节点v被访问。这也就意味着汇合节点w能够先于v被访问。

调整Dijkstra算法

根据上面的推导,对于带有汇合节点的加权有向图的单源最短路径问题仍然可以使用Dijkstra算法,只需做一个局部的调整:在向外扩展节点时,如果其相邻节点中有汇合节点,则更新其对应的分支路径的距离,但是直至汇合节点满足了C函数可以计算完全的距离时才参与后续的最短距离节点的选择。

示例

以图三为例:

图三

其中e为汇合节点,其C函数为所有前置相邻节点构成的路径的总和。

以a为起始节点,其计算步骤如下:

  1. 初始化

    节点 a b c d e f g
    前序访问节点 Φ Φ Φ Φ Φ Φ Φ
    距离 +∞ +∞ +∞ +∞ +∞ +∞ +∞
    访问顺序
  2. 访问a节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a Φ Φ Φ Φ
    距离 0 5 6 +∞ +∞ +∞ +∞
    访问顺序 1

    可以发现,b是距离a路径最短的未访问节点。

  3. 访问b节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b? Φ Φ
    距离 0 5 6 15 6? +∞ +∞
    访问顺序 1 2

    可以发现,b的邻居节点中存在汇合节点e,我们只更新通过b到e的路径的距离,因为还有一个前继节点形成的路径暂时不确定,所以无法计算e的距离,因此e不参与下一轮的选择。
    排除e之后,c是距离a路径最短的未访问节点。

  4. 访问c节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b+c c Φ
    距离 0 5 6 15 6+8=14 11 +∞
    访问顺序 1 2 3

    更新c到e的路径的距离,就可以计算a到e的距离了。
    可以发现,f是距离a路径最短的未访问节点。

  5. 访问f节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b+c c f
    距离 0 5 6 15 6+8=14 11 16
    访问顺序 1 2 3 4

    可以发现,e是距离a路径最短的未访问节点。

  6. 访问e节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b+c c e
    距离 0 5 6 15 6+8=14 11 15
    访问顺序 1 2 3 5 4

    因为从e到g的距离比从f到e更近,因此更新g。
    可以发现,d是距离a路径最短的未访问节点。

  7. 访问d节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b+c c e
    距离 0 5 6 15 6+8=14 11 15
    访问顺序 1 2 3 6 5 4

    因为从d到g的距离比从e到g更远,因此不用更新g。
    可以发现,g是距离a路径最短的未访问节点。

  8. 访问g节点并更新其相邻节点的距离

    节点 a b c d e f g
    前序访问节点 Φ a a b b+c c e
    距离 0 5 6 15 6+8=14 11 15
    访问顺序 1 2 3 6 5 4 7

    至此,图中所有节点都已被访问。

我们可以发现,从a到g的最短路径是经过汇合节点e形成的路径,其距离为15。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容