【问题标题】:Maximum recursion depth exceeded in dfs using recursion in python使用python中的递归在dfs中超出了最大递归深度
【发布时间】:2018-03-23 15:51:52
【问题描述】:

我编写了一个 python 代码来解决传教士和食人者问题,在 python 中使用递归 dfs。但是我不断收到此错误: RecursionError: 超出最大递归深度

我不知道该怎么办,而且我已经坚持了这么久。 任何帮助或建议都将挽救我的生命。谢谢。 代码如下:

class State(object):
#left = 1
#right = 0 for boat
        def __init__(self, missionaries, cannibals, boat):
    self.missionaries = missionaries
    self.cannibals = cannibals
    self.boat = boat

#def __str__(self):
#    return "%s, %s %s %s" % (self.by_move, self.missionaries, self.cannibals, self.boat)

def is_valid(self):
    if self.missionaries < 0 or self.missionaries > 3:
        return False
    if self.cannibals < 0 or self.cannibals > 3:
        return False
    if self.boat > 1 or self.boat < 0:
        return False
    if self.missionaries < self.cannibals and self.missionaries > 0:
        return False
    # Check for the other side
    if self.missionaries > self.cannibals and self.missionaries < 3:
        return False

    return True

def is_goal(self):
    return self.missionaries == 0 and self.cannibals == 0 and self.boat == 0

def new_states(self):
    op = -1  # Subtract
    boat_move = "from left shore to right"
    if self.boat == 0:
        op = 1  # Add
        boat_move = "from right shore to left"

    for x in range(3):
        for y in range(3):
            by_move = "Move %s missionaries and %s cannibals %s" % (x, y, boat_move)
            new_state = State(self.missionaries + op * x, self.cannibals + op * y, self.boat + op * 1)
            if x + y >= 1 and x + y <= 2 and new_state.is_valid():
                yield new_state

class Node(object):
def __init__(self, parent, state, depth):
    self.parent = parent
    self.state = state
    self.depth = depth

def children(self):
    for state in self.state.new_states():
        yield Node(parent=self, state=state, depth=self.depth + 1)

def extract_solution(self):
    print
    "Extracting soln"
    solution = []
    node = self
    solution.append(node)
    while node.parent is not None:
        solution.append(node.parent)
        node = node.parent
    solution.reverse()
    return solution

def dfs(root,visited,sol = None):
if root in visited:
    return
if root is None:
    return
visited.append(root)
if root.state.is_goal():
    sol = root
    return

for child in root.children():
    if child not in visited:
        dfs(child,visited,sol)

def main():
    initial_state = State(3,3,1)
    root = Node(parent = None, state = initial_state,depth = 0)
    visited = []
    sol = Node(parent = None, state = initial_state,depth = 0)
    dfs(root,visited,sol)
    ans = sol.extract_solution()
    print(ans)


if __name__ == '__main__':
    main()

【问题讨论】:

  • 请修正缩进。如果缩进错误,我们无法判断您的代码实际上做了什么。
  • Python 的默认递归深度是 1000。可以增加该限制,但如果逻辑正确,您的 DFS 应该不需要需要深度递归(除非您有大量传教士和食人者)。
  • 我的回答不清楚吗?如果是这样,您需要什么帮助?

标签: python recursion depth-first-search


【解决方案1】:

有两个问题:

1:您的“已访问”列表未正确跟踪所有状态。这可以通过将访问过的全局变量轻松解决(通过将其放在 def main() 前面,就像在最终解决方案中所做的那样)

2:该程序正在寻找无济于事的可能性(例如:让同一个人来回走动),这个

if root in visited:
    return
if root is None:
    return

没有解决这个问题,因为它从来都不是同一个根对象(即使 root.state.missionaries、食人者和船是相同的值),所以我使用字典对象更改了它:

if root is None:
    return
state = str(root.state.missionaries) + ',' + str(root.state.cannibals) + ',' + str(root.state.boat)
if state in routes:
    if routes[state] < root.depth:
        return
    else:
        routes[state] = root.depth
else:
    routes[state] = root.depth
visited.append(root)

这导致以下代码(它返回一个答案,我不确定它是否正确,因为我不知道传教士和食人者的问题)

class State(object):
#left = 1
#right = 0 for boat
    def __init__(self, missionaries, cannibals, boat):
        self.missionaries = missionaries
        self.cannibals = cannibals
        self.boat = boat

    #def __str__(self):
    #    return "%s, %s %s %s" % (self.by_move, self.missionaries, self.cannibals, self.boat)

    def is_valid(self):
        if self.missionaries < 0 or self.missionaries > 3:
            return False
        if self.cannibals < 0 or self.cannibals > 3:
            return False
        if self.boat > 1 or self.boat < 0:
            return False
        if self.missionaries < self.cannibals and self.missionaries > 0:
            return False
        # Check for the other side
        if self.missionaries > self.cannibals and self.missionaries < 3:
            return False

        return True

    def is_goal(self):
        return self.missionaries == 0 and self.cannibals == 0 and self.boat == 0

    def new_states(self):
        op = -1  # Subtract
        boat_move = "from left shore to right"
        if self.boat == 0:
            op = 1  # Add
            boat_move = "from right shore to left"

        for x in range(3):
            for y in range(3):
                by_move = "Move %s missionaries and %s cannibals %s" % (x, y, boat_move)
                new_state = State(self.missionaries + op * x, self.cannibals + op * y, self.boat + op * 1)
                if x + y >= 1 and x + y <= 2 and new_state.is_valid():
                    yield new_state

class Node(object):
    def __init__(self, parent, state, depth):
        self.parent = parent
        self.state = state
        self.depth = depth

    def children(self):
        for state in self.state.new_states():
            yield Node(parent=self, state=state, depth=self.depth + 1)

    def extract_solution(self):
        print "Extracting soln"
        solution = []
        node = self
        solution.append(node)
        while node.parent is not None:
            solution.append(node.parent)
            node = node.parent
        solution.reverse()
        return solution

def dfs(root,sol = None):
    if root is None:
        return
    state = str(root.state.missionaries) + ',' + str(root.state.cannibals) + ',' + str(root.state.boat)
    if state in routes:
        if routes[state] < root.depth:
            return
        else:
            routes[state] = root.depth
    else:
        routes[state] = root.depth
    visited.append(root)

    if root.state.is_goal():
        sol = root
        return

    for child in root.children():
        if child not in visited:
            dfs(child,sol)

visited = []
routes = {}

def main():
    initial_state = State(3,3,1)
    root = Node(parent = None, state = initial_state,depth = 0)
    sol = Node(parent = None, state = initial_state,depth = 0)
    dfs(root,sol)
    ans = sol.extract_solution()
    print(ans)


if __name__ == '__main__':
    main()

PS。正如@PM 2Ring 所说,下次:请在提问时修正你的缩进,它使阅读你的代码更容易理解。您可以通过选择所有代码、将选项卡添加到所有选定的行然后复制它来执行此操作。在粘贴之前,请确保有一个空行。 :)

【讨论】:

  • 非常感谢内森!你为我省去了很多麻烦 :) 并感谢有关缩进的提示。这是我第一次询问堆栈溢出问题,我努力修复缩进。将来会确保正确修复它。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2018-03-31
相关资源
最近更新 更多