【问题标题】:How can graph search return a path?图搜索如何返回路径?
【发布时间】:2021-05-16 14:11:40
【问题描述】:

我最近在学习图搜索和树搜索,看到很多例子提到“xxx图搜索返回的路径是......” 但是,图搜索是一种遍历方法,它如何返回路径?

我们知道在树搜索中,每个节点对应一个特定的路径,通过访问一个节点,我们知道对应的路径。我对树搜索足够熟悉,但是,在图形搜索中,目的是访问目的地,而不是找到通往目的地的路径。那么,如何定义图搜索返回的路径呢?

例如,下面是一个图表。

Graph
       B
      / \
     /   \
Start     Destination
     \   /
      \ /
       C

当我们在开始时做 BFS 时,访问顺序是 Start-B-C-DestinationStart-C-B-Destination。那么,返回的路径应该是什么?如果我们使用队列,我们​​可以说我们在访问B(或C)时加入了Destination,所以返回的路径是Start-B-Destination(或Start-C-Destination),那么下图呢?

Graph
       B
      / \
     /   \
Start-----D-----Destination
     \   /
      \ /
       C

很明显,D 在访问Start 时被排队,所以唯一可能的路径应该是Start-D-Destination?

A* 搜索存在更多问题。如果不是从最短路径访问节点(由于启发式函数不佳),那么最终返回的路径应该是什么?比如下图中,访问顺序是Start-B-D-C-Destination,那么返回的路径应该是什么? Start-B-D-Destination 还是 Start-C-D-Destination?当B 在边缘时,我们访问了D,但是,当我们计算从StartD 的成本时,我们正在计算Start-C-D,成本应该是2 而不是3。

Graph
        B
       / \
      1   2
     /     \
Start       D--5--Destination
     \     /
      1   1
       \ /
        C

h(B) = 2, h(C) = 4, h(D) = 1

我认为所有这些问题都是由于图搜索的目的不是找到路径,而图搜索会导致在选择最终路径中应该包含哪个节点时出现歧义。

感谢您的耐心等待,如果有人能给我答案,我将不胜感激。

【问题讨论】:

  • 建议:阅读 Dijsktra 的算法en.wikipedia.org/wiki/Dijkstra%27s_algorithm
  • Dijkstra 的算法,作为一种图搜索算法,可以返回一条路径,因为我们知道如何获得到特定节点的最短路径。路径中 A 的前一个节点是更新 A 距离的节点。在像 BFS 这样的情况下,没有这种关系。

标签: search graph path breadth-first-search a-star


【解决方案1】:

我会用你的例子:

        B
       / \
      1   2
     /     \
Start       D--5--Destination
     \     /
      1   1
       \ /
        C

请注意,纯广度优先搜索不关注边权重(或成本)。在这种情况下,将其带到目的地的第一条路径可能是Start->B->D->Destination。 p>

它用一个布尔标志标记它访问的每个节点,以表明该节点已被访问,因此它不追求Start->B->Start->C->Start->... 为了记住成功的路径,我们必须在某处存储更多信息。一种简单的方法是标记每个节点,不仅使用visited 标志,还使用对访问它的节点的引用。因此,如果访问顺序是Start, B, C, D, Destination,则图表看起来像这样:

        B(Start)
       / \
      1   2
     /     \
Start       D(B)--5--Destination(D)
     \     /
      1   1
       \ /
        C(Start)

然后我们可以回溯。我们是如何到达Destination 的?来自D。我们是如何到达D 的?来自B。我们是如何到达B 的?来自Start

广度优先搜索跟随队列中的第一条边,并找到最短路径(在边数最少的意义上)。如果我们想要最小权重 (cheapest) 路径,我们修改搜索以跟踪 cost-to-get-to-this-node,并沿着最便宜地到达新节点的边. (这是 Dijkstra 算法的一个版本。)那么在这种情况下,访问顺序将是相同的,但我们将从C 访问D,而不是从B,并获取路径Start->C->D->Destination

用A*,使用h(B) = 2, h(C) = 4, h(D) = 1,访问顺序为Start, B, D, C, D, Destination,路径为Start->C->D->Destination

【讨论】:

  • 感谢您的解释!我想我理解了大部分内容。所以,根据你的回答,在我的第二张图中,如果我们使用 BFS,唯一可能的路径是 Start-D-Destination,如果我们使用 DFS,这三个路径都是可能的,对吧?
【解决方案2】:

对于 BFS,有两种选择:

  1. 当您将一个节点加入队列时,请标记您来自哪个邻居。那么最后,最佳路径上的每个节点都会有一个指向路径上“前一个”节点的链接,因此您可以直接从 Destination 回溯到 Start 以找到路径。

  2. 当您将一个节点加入队列时,请记下到该节点的最佳路径,这只是到其邻居的最佳路径,加上您选择的边。

选项 1 是通常的做法,因为它的性能更高。


对于 Dijkstra(加权图的 BFS)也是如此,除了当您将一个节点排入队列并注意您来自哪个邻居时,您不一定找到该节点的最佳路径. 如果以后遇到来自不同邻居的同一个节点,则需要比较两条路径的总距离,选择较短的一个作为“前一个”节点。

这是在pseudocode on Wikipedia 的第 18-20 行完成的

18  if alt < dist[v]:              
19    dist[v] ← alt
20    prev[v] ← u

一旦您扩展节点(将其从优先级队列中删除),您就可以保证找到该节点的最佳路径。


对于 A*,如果启发式是 consistent,情况与 Dijkstra 的情况相同。但是,如果启发式只是admissible,那么保证您在第一次展开节点时找到了最佳路径。在这种情况下,您可能需要多次入队和扩展同一个节点。

因此,将 A* 与不一致的启发式结合使用实际上并不常见。

【讨论】:

  • 谢谢!我认为我没有正确理解 A* 搜索,因为我没有认识到在 A* 搜索中可以多次访问一个节点。
  • 是否意味着即使启发式函数不一致,A*搜索最终也能返回最短路径?
  • @citrate:如果启发式是一致的,则 A* 保证返回最短路径,并且无论何时扩展节点,它都保证是到该节点的最短路径。如果启发式是可接受的但不一致,那么 A* 保证返回最短路径,但节点可能需要扩展多次。如果启发式不可接受,它可能不会返回最短路径(这实际上是一些其他算法的优势,但这是另一个讨论)
猜你喜欢
  • 1970-01-01
  • 2020-06-22
  • 2011-11-14
  • 1970-01-01
  • 2012-06-07
  • 2022-11-10
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
相关资源
最近更新 更多