双向搜索

AAT*_*AAT 3 python breadth-first-search python-3.x bidirectional-search

我正在尝试用 python 实现双向搜索。

据我了解,我应该以某种方式合并两个广度优先搜索,一个从起始(或根)节点开始,一个从目标(或结束)节点开始。当两个广度优先搜索在同一顶点“相遇”时,双向搜索终止。我已经实现了BFS,代码如下

def bfs(graph, start):
    path = []
    queue = [start]
    while queue:
        vertex = queue.pop(0)
        if vertex not in path:
            path.append(vertex)
            queue.extend(graph[vertex])
    return path
Run Code Online (Sandbox Code Playgroud)

您能为我提供一个代码示例(Python 语言)或双向图搜索代码的链接吗?

And*_*ell 7

这似乎是一个有趣的问题,所以我尝试了一下。这是我的尝试。你没有说你的图表是什么格式,所以我猜是一个像下面这样的字典:

example_graph = {0:[1,2], 1:[0,3,4], 3:[1], 4:[1], 2:[0,5,6], 5:[2], 6:[2]}
Run Code Online (Sandbox Code Playgroud)

该代码从指定的起始顶点和目标顶点开始运行当前活动顶点的列表,并记住如何通过 {vertices :lists} 字典到达它们。如果一个活动顶点发现自己紧邻另一个活动顶点且路径从另一端开始,则它会合并列表并返回结果,否则它会扩展所有路径并继续。

def bi_directional_search(graph, start, goal):
    # Check if start and goal are equal.
    if start == goal:
        return [start]
    # Get dictionary of currently active vertices with their corresponding paths.
    active_vertices_path_dict = {start: [start], goal: [goal]}
    # Vertices we have already examined.
    inactive_vertices = set()

    while len(active_vertices_path_dict) > 0:

        # Make a copy of active vertices so we can modify the original dictionary as we go.
        active_vertices = list(active_vertices_path_dict.keys())
        for vertex in active_vertices:
            # Get the path to where we are.
            current_path = active_vertices_path_dict[vertex]
            # Record whether we started at start or goal.
            origin = current_path[0]
            # Check for new neighbours.
            current_neighbours = set(graph[vertex]) - inactive_vertices
            # Check if our neighbours hit an active vertex
            if len(current_neighbours.intersection(active_vertices)) > 0:
                for meeting_vertex in current_neighbours.intersection(active_vertices):
                    # Check the two paths didn't start at same place. If not, then we've got a path from start to goal.
                    if origin != active_vertices_path_dict[meeting_vertex][0]:
                        # Reverse one of the paths.
                        active_vertices_path_dict[meeting_vertex].reverse()
                        # return the combined results
                        return active_vertices_path_dict[vertex] + active_vertices_path_dict[meeting_vertex]

            # No hits, so check for new neighbours to extend our paths.
            if len(set(current_neighbours) - inactive_vertices - set(active_vertices))  == 0:
                # If none, then remove the current path and record the endpoint as inactive.
                active_vertices_path_dict.pop(vertex, None)
                inactive_vertices.add(vertex)
            else:
                # Otherwise extend the paths, remove the previous one and update the inactive vertices.
                for neighbour_vertex in current_neighbours - inactive_vertices - set(active_vertices):
                    active_vertices_path_dict[neighbour_vertex] = current_path + [neighbour_vertex]
                    active_vertices.append(neighbour_vertex)
                active_vertices_path_dict.pop(vertex, None)
                inactive_vertices.add(vertex)

    return None
Run Code Online (Sandbox Code Playgroud)