我整个星期都在尝试这一点,但在我的生活中,我不能想出来。
我知道我需要一个辅助函数来递归并返回pathSoFar。我似乎无法理解递归。
我很困惑,除了递归之外,我甚至无法确切地解决问题。
感谢您的帮助。
编辑:好的,我会澄清一下。令我困惑的一件事是当节点没有邻居时返回什么路径。可以首先返回目标路径,但是,因为帮助程序仍在递归,它可以返回死端路径。我想我对回溯感到困惑。答案 0 :(得分:6)
Wikipedia实际上有一些非常好的伪代码用于深度优先遍历。这些遍历算法使用它们在遍历中出现的顺序标记图中的所有节点。相反,您希望在找到目标时立即返回目标路径。
让我们修改维基百科算法:
( INCORRECT ALGORITHM DELETED WHICH THE OP COMMENTED ON CORRECTLY BELOW )
这是一个Python实现:
g = {
'A': ['B', 'C', 'D'],
'B': ['C', 'E', 'F'],
'C': ['A'],
'D': ['B', 'F', 'G', 'H'],
'E': ['G'],
'F': ['A', 'F'],
'G': ['H', 'I'],
'H': [],
'I': []
}
def DFS(g, v, goal, explored, path_so_far):
""" Returns path from v to goal in g as a string (Hack) """
explored.add(v)
if v == goal:
return path_so_far + v
for w in g[v]:
if w not in explored:
p = DFS(g, w, goal, explored, path_so_far + v)
if p:
return p
return ""
# Hack unit test
assert DFS(g, 'A', 'I', set(), "") == "ABEGI"
assert DFS(g, 'A', 'E', set(), "") == "ABE"
assert DFS(g, 'B', 'B', set(), "") == "B"
assert DFS(g, 'B', 'B', set(), "") == "B"
assert DFS(g, 'A', 'M', set(), "") == ""
assert DFS(g, 'B', 'A', set(), "") == "BCA"
assert DFS(g, 'E', 'A', set(), "") == ""
这里的想法是,您希望在图g
中找到从v
到goal
的路径,因为您已经沿path_so_far
路径前进}。 path_so_far
实际上应该在v
之前结束。
如果目标是v
,那么您可以将v
添加到目前为止的路径,就是这样。
否则,您将需要探索从v
发出的所有边缘,这些边缘尚未在边缘的另一端探索过节点。对于这些边缘中的每一个,您可以使用到目前为止的路径(当前节点)进行搜索(递归)。如果v
没有通往目标的路径,您将返回空路径。
好处是你使用递归来“自动回溯”,因为你将增强路径传递给你的递归调用。
答案 1 :(得分:1)
递归是指将问题减少为一系列较小的问题。
在这种情况下,假设您正在尝试查找从节点A到节点Z的路径。首先,您要查看A的邻居。假设它们是B,C和D.
现在你有三个子问题:找到从B到Z,C到Z和D到Z的路线。如果你能解决其中任何一个问题,你也解决了从中找到路径的更大问题A到Z。
所以,你递归。你在B,C和D上使用你的findPath方法,给每个人一个包含A的节点列表 - 以防止它们向后移动[1]。如果他们中的任何一个说“我找到了一条路”,你就会走这条路,他们会回来,在一开始就把A贴上,并称之为一天。
在递归调用中,最终您会发现自己处于Z的邻居节点(如果A和Z实际连接)。当发生这种情况时,您已解决了问题:返回该链接。如果你最终到达一个已经访问过每个邻居的死端节点,那么返回一些代码,让你的调用者知道它是一个死胡同,他们不应该使用该节点来尝试构建一个解决方案。
[1]旁注:如果你非常聪明,你也会把B放在你传递给C上的递归调用的列表中,并将B + C放在你传递给D的列表中。