【问题标题】:Shortest path with a twist转折的最短路径
【发布时间】:2017-05-23 11:09:31
【问题描述】:

我在它们之间有n 顶点和m 无向加权边(权重代表分钟)。每个顶点包含在该顶点上喝咖啡所需的分钟数。

我想确定从顶点v 到顶点w 所需的最短时间(分钟),但还有一个额外的限制是我必须在途中的一个顶点上喝咖啡vw)。

示例

(顶点中的数字是喝一杯咖啡所需的分钟数,边上的权重表示经过这条边所需的分钟数)

vw 途中喝杯咖啡,输出最少的必要时间(输出应该是30)。

我目前的方法是用 Dijkstra 找到最短路径(将该路径上所有边的权重相加),然后将该路径上咖啡时间最短的顶点的值相加到我的结果是为了获得从vw 所需的总时间。

我的方法不起作用,这是我的方法失败的例子(我的方法的结果是12分钟,实际结果应该是6分钟):

如何确定从顶点vw 的最短时间,并限制我需要在路上喝咖啡?

【问题讨论】:

  • 这似乎是math.stackexchange.com的问题
  • 这是我在编程面试时收到的一个问题。
  • 最好在问题中说明这一点,但我仍然相信这在数学交流中会更好。
  • 带有“9”的顶点是否连到了图上?

标签: java algorithm graph-algorithm shortest-path dijkstra


【解决方案1】:

解决这个问题的标准方法是:

  1. 制作 2 份图表副本 - need_coffee 版本和 had_coffee version

  2. 将每个 need_coffee 节点与对应的 had_coffee 节点连接起来,边成本等于在该节点喝咖啡的成本。

  3. 使用 Dijkstra 算法找到从V_need_coffeeW_had_coffee 的最短路径

【讨论】:

  • 这个问题有名字吗?我在哪里可以了解更多关于它的信息,也许可以找到这个标准解决方法的更详细描述?
  • 不仅仅是这个问题,还有很多类似的问题,你必须找到一条最短路径以及其他标准。我听说过一种称为“图形分层”的技术,但我不知道它是否有一个标准名称。这里有一个很好的讨论:youtube.com/…
  • 你的算法解决方案总是那么有见地
  • 此解决方案优雅、直接且适合我,我只是不明白您解决此问题的方法与您引用的视频之间的联系?
  • 视频展示了使用相同的技术实现“
【解决方案2】:

一种方法如下:

  1. 计算从 u 到所有其他顶点的最短路径并将其称为 p(u,x)
  2. 计算从所有顶点到 v 的最短路径并将其称为 p(x,v)
  3. 遍历所有顶点并找到值的最小值 (p(u,x)+coffee(x)+p(x,v))

这样做会导致算法的时间复杂度与 Dijkstra 的算法相同(如果您在步骤 1 和 2 中使用 Dijkstra 算法)

【讨论】:

  • 你的方法为每个节点运行 Dijkstra (O(E * logV)) 2 次,复杂度不应该是 O(V * E * logV) 吗?
  • Dijkstra 的算法能够计算从一个节点到所有其他节点的最短路径,例如参见维基页面
  • 更准确的可以看一下en.wikipedia.org/wiki/…
  • 所以在第 1 步中,您的算法运行一次 Dijkstra(确定从 u 到所有其他顶点的最短路径),在第 2 步中,您运行 Dijkstra 以确定从 v 到所有其他顶点的最短路径。在第 3 步中,您遍历所有节点并计算 p(u,x)+coffee(x)+p(x,v),保存最小值并在最后输出。总的来说,这会运行 Dijkstra 2 次并遍历所有节点一次。我没听错吗?
  • 是的,就是这样!
【解决方案3】:

我会尝试编写一个 A* 算法来解决这个问题。当你扩展一个节点时,你会为每个输出顶点得到两个孩子;一个你喝咖啡的地方,一个你不喝的地方。如果您使用 Dijkstra 的运行对您的算法进行预处理(因此您已经预先计算了最短路径),那么您可以使用 Dijkstra 的最短路径 + 喝咖啡的最短时间(如果咖啡已经喝完,则为 + 0)告知 A* 搜索的启发式.

当您不仅到达目标节点而且还喝了咖啡时,A* 搜索终止(您已达到目标)。

第二种情况的搜索示例:

Want: A --> C

A(10) -- 1 -- B(10) -- 1 -- C(10)
 \                           /
  \                         /
   2 -------- D(2) ------- 2   



Expand A
  A*(cost so far: 10, heuristic: 2)          total est cost: 12
  B (cost so far: 1, heuristic: 1 + 2)       total est cost: 3
  B*(cost so far: 11, heuristic: 1)          total est cost: 12
  D (cost so far: 2, heuristic: 2 + 2)       total est cost: 6
  D*(cost so far: 14, heuristic: 2)          total est cost: 16
  Expand B
    A*(cost so far: 12, heuristic: 2)        total est cost: 14
    B*(cost so far: 11, heuristic: 1)        total est cost: 12
    C(cost so far: 2, heuristic: 2)          total est cost: 4
    C*(cost so far: 12, heuristic: 0)        total est cost: 12
    Expand C
      B*(cost so far: 13, heuristic: 1)      total est cost: 14
      C*(cost so far: 12, heuristic: 0)      total est cost: 12
  Expand D
    A* (cost so far: 14, heuristic: 2)       total est cost: 16
    D* (cost so far: 4, heuristic: 2)        total est cost: 6
    C  (cost so far: 4, heuristic: 0 + 2)    total est cost: 6
    C* (cost so far: 6, heuristic: 0)        total est cost: 6
    Expand C*
       goal reached.                         total cost: 6

Key:
  * = Coffee from parent was drunk

所以你可以看到这个算法会首先尝试沿着 Dijkstra 的最短路径走(从不喝咖啡)。然后当它到达终点时,它会看到一个物理目标状态,但仍然需要喝咖啡。当它将这个物理目标状态扩展为喝咖啡时,它会发现到达的成本不是最优的,因此它会从另一个分支继续搜索并继续前进。

请注意,在上面,A 和 A* 是不同的节点,因此您可以通过某种方式重新访问父节点(但前提是咖啡饮用状态不同)。 这是为了解决这样的图表:

Want A-->B

A(20) -- 1 -- B(20)
  \
   2
    \
    C(1)

从 A->C->C*->A*->B* 出发有意义的地方

我还不确定我们是否需要通过我们喝咖啡的节点来区分“喝咖啡”状态,但我倾向于不需要。

【讨论】:

  • 有趣的方法,看起来不错(我想不出反例)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多