扭曲的最短路径

时间:2017-05-23 11:09:31

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

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

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

示例

(顶点中的数字是喝咖啡所需的分钟数,边缘上的重量代表了此边缘所需的分钟数)

vw并在途中喝咖啡,输出最短的必要时间(输出应为30)。

enter image description here

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

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

Counterexample for my approach

如何确定从顶点vw的最短时间,以及我需要在路径上喝咖啡的约束?

3 个答案:

答案 0 :(得分:7)

解决此问题的标准方法是:

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

  2. 将每个need_coffee节点与相应的had_coffee节点相连,边缘成本等于该节点喝咖啡的成本。

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

答案 1 :(得分:1)

我会尝试编写一个A *算法来解决这个问题。展开节点时,每个传出顶点都会有两个子节点;一个你喝咖啡的地方,另一个你不喝咖啡的地方。如果你使用Dijkstra(你已经有预先计算的最短路径)对算法进行预处理,那么你可以通过Dijkstra的最短路径+最短时间通知A *搜索的启发式算法。喝咖啡(如果咖啡已经喝完,可以喝+0)。

当您不仅到达目的地节点,而且还喝了咖啡时,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 *

开始是有意义的

我还不确定我们是否需要区分“喝咖啡”#34;我们在哪个节点喝咖啡,但我倾向于否。

答案 2 :(得分:1)

一种方法如下:

  1. 计算从u到所有其他顶点的最短路径并称之为p(u,x)
  2. 计算从所有顶点到v的最短路径,并将其称为p(x,v)
  3. 遍历所有顶点并找到值的最小值(p(u,x)+ coffee(x)+ p(x,v))
  4. 这样做会导致算法与Dijkstra的算法具有相同的时间复杂度(如果你在步骤1和2中使用Dijkstra的算法)