【问题标题】:How to understand this priority queue depth-first search?如何理解这种优先队列深度优先搜索?
【发布时间】:2021-04-02 15:11:13
【问题描述】:

以下是伪代码实现深度优先搜索(DFS),使用一个堆栈和一个大表来标记访问过的节点:

DFS(N0):
   StackInit(S)
   S.push((N0, null))
   if isGoal(N0) then do
      return true
   markVisited(N0)
   S.push((null, N0))
   while !isEmpty(S) then do
      (N, parent) := S.pop()
      R := next((N, parent))
      if isNull(R) then do
         continue             // So no new node add to this layer.
      S.push((R, parent))
      if marked(R) then do
         continue
      if isGoal(R) then do    // If it's goal don't have to explore it.
         return true
      markVisited(R)
      if depthMax((R, parent)) then do
         continue
      S.push((null, R))
   return false

我要解决的问题是对其进行修改:它将堆栈 S 替换为 PriorityQueue PQ。该算法用于模拟IDA*算法(这在教科书中有说明,可惜不是用英文写的,所以我不会提供参考/书名):


DFS2(N0, f, LIMIT):
   PriorityQueueInit(PQ)
   // A node (N, parent) stored in PQ represents a path from `N0` to `N`\
        passing the node `parent`; A node with smaller value on f() is \
        prioritized than those with larger value.
   PQ.push((N0, null))
   if isGoal(N0) then do
      return true
   markVisited(N0)
   PQ.push((null, N0))
   while !isEmpty(PQ) then do     // (1)
      (N, parent) := PQ.poll()
      R := next((N, parent))      // (2)
      if isNull(R) then do
         continue
      PQ.offer((R, parent))
      if marked(R) then do
         continue
      if isGoal(R) then do
         return true
      markVisited(R)
      if f((R, parent)) > LIMIT then do
         continue
      PQ.offer((null, R))
   return false
  • (1):在A*算法中,优先级队列用于存储还没有被探索过的节点,即open list。虽然在我提供的第一个 DFS 伪代码中,堆栈 S 是关闭列表,所以我假设在第二个伪代码中 PQ 也是关闭列表。那么第二个伪代码如何模拟 IDA* 算法,并带有一个关闭列表?
  • (2):它从PQ 获取当前最小的节点,这可能不是节点N 的兄弟,即它从当前子树跳转到另一个包含N 的子树.这条线的目的是什么?

谁能告诉我第二种算法的正确性,即为什么它可以用于 IDA* 算法?


更新了更多信息:我在这个问题上花费了很多时间和精力,但由于以下几点,它似乎非常困难:

  1. 教科书中出现的所有图表都是树状绘制的,即每个节点只有一个父节点,以显示概念。这让我很困惑:第二种算法是否只适用于树?

  2. 考虑线

    if f((R, parent)) > LIMIT then do ...
    

    如果第二个也适用于图形,而不仅仅是树,那么可能会有很多父母去R,我应该考虑所有情况还是只考虑当前的情况,parent

【问题讨论】:

  • (之前没遇到过Iterative Deepening A*。你能指出为什么simulateperform更合适 i> / 实现?)
  • @greybeard:是的,我的意思是,DFS2(N0, f, LIMIT) 可以用来实现迭代深化 A*。
  • 由于这篇文章中有几个问题,我不确定您期望得到什么样的答案。回答正确需要哪些分数?
  • @TomerShetah:我的困惑是我不相信第二种算法会实现 IDA* 算法。所以你只能回答这一行:“谁能告诉我第二种算法的正确性,即为什么它可以用于 IDA* 算法?”
  • @TomerShetah:不客气。

标签: algorithm search priority-queue depth-first-search


【解决方案1】:

这里发生了很多事情。

据我所知,这段代码总是返回到达队列顶部的第一个目标节点。在下面关于 f 和 next 的假设下,这个目标节点是 f 最优的。但我不会称之为 IDA*。

首先,通常 A* 和 IDA* 都会同时打开当前节点的所有邻居。这段代码......没有。它使用迭代器,但只有一个循环。第一次推送是针对当前节点的下一个兄弟节点,第二次推送是针对子节点。这很好,我想,除了兄弟姐妹应该以递增的 f 顺序枚举,这样一个有前途的兄弟姐妹就不会在一个没有前途的兄弟姐妹之后被隐藏。

其次,与 A* 不同,IDA* 没有关闭列表。从某种意义上说,IDA* 总是有一个搜索,因为如果它到达两个等效节点,它仍然将它们视为不同的节点。 A* 确实有一个关闭列表,但它比这里提供的更复杂。 A* 处理循环的方式是,如果它发现到已经关闭的节点的更便宜的路径,那么它会重新打开该节点。这段代码没有,所以只有在不需要重新打开节点时它才是正确的。因此,此代码需要 f 是所谓的一致启发式(在每条路径上,f 永远不会随着您遵循路径而下降),而 A* 只需要 f 是可接受的(f 永远不会低估达到目标的成本州)。

【讨论】:

  • "首先,通常 A* 和 IDA* 都会同时打开当前节点的所有邻居。"是的!我得出了同样的结论。我看了Single Source Dijkstra最短路径算法的证明,证明中的重点是这个。
  • R := next((N, parent)) // (2)next()确实是按照你的意思f-order。
  • 从你的回答我确定书中提供的代码是错误的,我会联系老师(也是本书的作者)来确定这一点。赏金来啦~
猜你喜欢
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 2012-05-23
相关资源
最近更新 更多