【问题标题】:Depth-First search in PythonPython中的深度优先搜索
【发布时间】:2011-01-09 09:53:56
【问题描述】:

我正在尝试在 Python 中进行深度优先搜索,但它不起作用。

基本上我们有一个钉子纸牌板:

[1,1,1,1,1,0,1,1,1,1]

1 代表一个挂钩,0 是一个空位。您必须一次将一个钉子向后或向前移动两个槽位到一个空位。如果您在此过程中跳过另一个挂钩,它将成为一个空槽。你这样做直到剩下一个钉子。所以基本上,游戏是这样的:

[1, 1, 1, 1, 1, 0, 1, 1, 1, 1]
[1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 1, 0, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1, 0, 1] #etc until only 1 peg left

这是我所拥有的:

class MiniPeg():
    def start(self):
        ''' returns the starting board '''
        board = [1,1,1,1,1,0,1,1,1,1]
        return board

    def goal(self, node):
        pegs = 0

        for pos in node:
            if pos == 1:
                pegs += 1

        return (pegs == 1) # returns True if there is only 1 peg

    def succ(self, node):
        pos = 0
        for peg in node:
            if peg == 1:                
                if pos < (len(node) - 2):  # try to go forward
                    if node[pos+2] == 0 and node[pos+1] == 1:
                        return create_new_node(node, pos, pos+2)

                if pos > 2: # try to go backwards 
                    if node[pos-2] == 0 and node[pos-1] == 1:
                        return create_new_node(node, pos, pos-2)
        pos += 1

def create_new_node(node, fr, to):
    node[fr] = 0
    node[to] = 1
    if fr > to:
        node[fr-1] = 0
    else:
        node[fr+1] = 0
    return node

if __name__ == "__main__":
    s = MiniPeg()
    b = s.start()

    while not s.goal(b):
        print b
        b = s.succ(b)

那么,现在我的问题是:

  1. 这是进行深度优先搜索的正确方法吗?
  2. 我的算法不起作用!!!它卡住了。在向这里提问之前,我已经为此苦苦挣扎了好几天,所以请帮忙。
  3. 看来我没有关注 DRY,有什么建议吗?
  4. 天哪,帮帮我吧?

【问题讨论】:

    标签: python depth-first-search


    【解决方案1】:

    您似乎不是在创建新节点,只是重新使用现有节点。 DFS 需要某种堆栈(调用堆栈或您自己的堆栈)。那是哪里?

    【讨论】:

    • 是的,它应该使用“产量”生成器或其他东西,但我遇到了麻烦,所以我使用了回报。那你能帮我指出正确的方向吗,我很困惑。
    【解决方案2】:

    嗯,首先深度优先搜索假设一棵树。现在,这是有道理的,因为在大多数情况下你有几个可能的动作。深度优先搜索将简单地尝试第一个可能的移动,然后尝试在新情况下的第一个可能的移动,以及在新情况下的第一个可能的移动,直到成功或没有更多可能的移动,在这种情况下它会备份直到它找到了一个它没有尝试过的动作,然后再次下降。

    “正确”的做法是使用递归。据我所知,您的系统中没有递归。

    这样的事情会起作用(pythonic psuedo codeish english):

    def try_next_move(self, board):
        for each of the pegs in the board:
            if the peg can be moved:
                new_board = board with the peg moved
                if new_board is solved:
                    return True
                if self.try_next_move(new_board):
                    return True
                # That move didn't lead to a solution. Try the next.
        # No move  worked.
        return False
    

    【讨论】:

      【解决方案3】:

      在每一步都是从“棋盘位置”“移动”到某个可能的下一个位置直到达到目标的情况下,实现 DFS 的正常方法如下(伪代码)

      seenpositions = set()
      currentpositions = set([startingposition])
      while currentpositions:
        nextpositions = set()
        for p in currentpositions:
          seenpositions.add(p)
          succ = possiblesuccessors(p)
          for np in succ:
            if np in seenpositions: continue
            if isending(np): raise FoundSolution(np)
            nextpositions.add(np)
        currentpositions = nextpositions
      raise NoSolutionExists()
      

      您可能还希望保留反向链接,以便能够在最后发出一系列导致找到的解决方案(如果有的话)的移动,但这是一个辅助问题。

      我在您的代码中没有发现这种通用结构(或其合理变体)的痕迹。为什么不尝试以这种方式记录呢?您只需要编码possiblesuccessorsisending(如果您坚持将位置保留为列表,则必须将其转换为元组以检查集合中的成员资格并添加到集合中,但是,这非常小;- )。

      【讨论】:

      • 看起来不错。但是,您离收敛速度更快的 A* 算法仅一步之遥。您所需要的只是对目标的“剩余距离”(即移动次数)的启发式方法。看起来这个启发式可能只是剩下要翻转的引脚数。
      • 在将p 的继任者添加到currentpositions 之后,不应该将p 添加到seenpositions 吗?
      • @jellybean,是的,我确实忘记更新 seenpositions: tx 以进行发现——现在编辑修复。
      【解决方案4】:

      基本的算法问题是succ 函数对于给定的棋盘状态总是只产生一个可能的移动。即使有多个可能的移动,succ 函数也只会返回它可以找到的第一个。深度优先搜索需要处理每个状态下所有可能的移动。

      更多的问题可能来自这样一个事实:create_new_node,尽管它的名字,并没有真正创建一个新的节点,而是修改了现有的节点。对于深度优先搜索,如果此函数实际上创建了它作为参数获取的列表的副本,那么您希望在其周围保留前一个节点会更好。

      此外,当检查succ 中的倒退可能性时,您仅在pos &gt; 2 中尝试这样做。太严格了,pos &gt; 1 也可以。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多