广度优先搜索,图中目标的所有路径
Breath first search, all paths to a goal in a graph
我一边玩 BFS,一边尝试自学 Python 3. 目前我正在尝试在图表中获取从开始到目标的所有路径。
图表设置如下:
graph = {
A : [B, C],
B : [D, E],
C : [F],
F : [B]
}
所以,有一条从 F 到 B 的路径。我 运行 遇到的问题如下:由于某些节点设置为访问,算法无法 运行再次超过他们。当然,我可以更改它,但我想知道我应该使用什么 'stop' 条件。
我的代码是这样的:
initial = A
goal = D
# So there are 2 routes:
# A -> C -> F -> B -> D
# A -> B -> D
frontier = queue.Queue()
frontier.put(initial)
backtracker = { }
paths = []
# until I find a halting condition.
while True:
node = frontier.get()
print('Popping: ' + node.name)
node.isOpen = False
if node in graph:
for child in graph[node]:
print('Expanding: ' + node.name + ' -> ' + child.name)
backtracker.update( { child : node } )
if child.name == goal.name:
path = backtrack(backtracker, initial, goal)
paths.append(path)
backtracker = {}
goal.isOpen = True
initial.isOpen = True
frontier = queue.Queue()
frontier.put(initial)
if child.isOpen:
print('Putting: ' + child.name)
frontier.put(child)
所以在这种情况下,找到了路径 A -> B -> D,但这将 B 设置为关闭,因此算法无法再访问它来查找 A -> C -> F -> B -> D. 我开始绕圈子思考,所以任何提示(而不是提示然后是完整的解决方案!!!)将不胜感激。
让我们忽略 'A -> C -> F -> B -> A -> C -> F -> B -> D' 等情况(无论如何这是不可能的,因为没有定义从 B -> A 的路径)。
BFS 尝试构建生成树。如果你想在过程中得到最短路径,你可以在第一次找到目标节点时停止——这是BFS的典型用例。
但是如果你想找到所有条路径,我认为停止条件是你已经访问了所有节点,所以生成树是完整的 从您已经访问过的节点中没有您可以访问的其他节点。你不能早点停下来,因为即使是你要访问的最后一个节点,也可能有一条通向目标节点的单向边,揭示了一条新路径(尽管是最不理想的路径)。
在写上面的答案时,我可能只是部分理解了问题。如果你问的是最后生成路径,并给出类似
的配置
A--------->B-------->C
\ / \ /
\->D->/ \->E->/
你想找到所有的 ABC、ADBC、ABEC 和 ADBEC,我想你需要用递归的方式对这个 valid-paths-graph 做一个完整的遍历,一个 DFS(就在这个 sub-graph,所有可能的尝试都会生成一个有效路径)。因此 BFS-pass 可用于将原始图缩减为仅包含实际(可能是冗余)路径的图,但随后需要 DFS 来实际单独生成所有路径。
我一边玩 BFS,一边尝试自学 Python 3. 目前我正在尝试在图表中获取从开始到目标的所有路径。
图表设置如下:
graph = {
A : [B, C],
B : [D, E],
C : [F],
F : [B]
}
所以,有一条从 F 到 B 的路径。我 运行 遇到的问题如下:由于某些节点设置为访问,算法无法 运行再次超过他们。当然,我可以更改它,但我想知道我应该使用什么 'stop' 条件。
我的代码是这样的:
initial = A
goal = D
# So there are 2 routes:
# A -> C -> F -> B -> D
# A -> B -> D
frontier = queue.Queue()
frontier.put(initial)
backtracker = { }
paths = []
# until I find a halting condition.
while True:
node = frontier.get()
print('Popping: ' + node.name)
node.isOpen = False
if node in graph:
for child in graph[node]:
print('Expanding: ' + node.name + ' -> ' + child.name)
backtracker.update( { child : node } )
if child.name == goal.name:
path = backtrack(backtracker, initial, goal)
paths.append(path)
backtracker = {}
goal.isOpen = True
initial.isOpen = True
frontier = queue.Queue()
frontier.put(initial)
if child.isOpen:
print('Putting: ' + child.name)
frontier.put(child)
所以在这种情况下,找到了路径 A -> B -> D,但这将 B 设置为关闭,因此算法无法再访问它来查找 A -> C -> F -> B -> D. 我开始绕圈子思考,所以任何提示(而不是提示然后是完整的解决方案!!!)将不胜感激。
让我们忽略 'A -> C -> F -> B -> A -> C -> F -> B -> D' 等情况(无论如何这是不可能的,因为没有定义从 B -> A 的路径)。
BFS 尝试构建生成树。如果你想在过程中得到最短路径,你可以在第一次找到目标节点时停止——这是BFS的典型用例。
但是如果你想找到所有条路径,我认为停止条件是你已经访问了所有节点,所以生成树是完整的 从您已经访问过的节点中没有您可以访问的其他节点。你不能早点停下来,因为即使是你要访问的最后一个节点,也可能有一条通向目标节点的单向边,揭示了一条新路径(尽管是最不理想的路径)。
在写上面的答案时,我可能只是部分理解了问题。如果你问的是最后生成路径,并给出类似
的配置 A--------->B-------->C
\ / \ /
\->D->/ \->E->/
你想找到所有的 ABC、ADBC、ABEC 和 ADBEC,我想你需要用递归的方式对这个 valid-paths-graph 做一个完整的遍历,一个 DFS(就在这个 sub-graph,所有可能的尝试都会生成一个有效路径)。因此 BFS-pass 可用于将原始图缩减为仅包含实际(可能是冗余)路径的图,但随后需要 DFS 来实际单独生成所有路径。