Tracing and Returning a Path in Depth First Search

前端 未结 4 1954
青春惊慌失措
青春惊慌失措 2021-01-30 09:19

So I have a problem that I want to use depth first search to solve, returning the first path that DFS finds. Here is my (incomplete) DFS function:

    start = pr         


        
相关标签:
4条回答
  • 2021-01-30 09:35

    Not specific to your problem, but you can tweak this code and apply it to different scenarios, in fact, you can make the stack also hold the path.

    Example:

         A
       /    \
      C      B
      \     / \
       \    D E
        \    /
           F
    
    
    graph = {'A': set(['B', 'C']),
             'B': set(['A', 'D', 'E']),
             'C': set(['A', 'F']),
             'D': set(['B']),
             'E': set(['B', 'F']),
             'F': set(['C', 'E'])}
    
    
    
    
    def dfs_paths(graph, start, goal):
        stack = [(start, [start])]
        visited = set()
        while stack:
            (vertex, path) = stack.pop()
            if vertex not in visited:
                if vertex == goal:
                    return path
                visited.add(vertex)
                for neighbor in graph[vertex]:
                    stack.append((neighbor, path + [neighbor]))
    
    print (dfs_paths(graph, 'A', 'F'))   #['A', 'B', 'E', 'F']
    
    0 讨论(0)
  • 2021-01-30 09:45

    this link should help you alot ... It is a lengthy article that talks extensively about a DFS search that returns a path... and I feel it is better than any answer I or anyone else can post

    http://www.python.org/doc/essays/graphs/

    0 讨论(0)
  • 2021-01-30 09:47

    You are right - you cannot simply return the stack, it indeed contains a lot of unvisited nodes.

    However, by maintaining a map (dictionary): map:Vertex->Vertex such that parentMap[v] = the vertex we used to discover v, you can get your path.

    The modification you will need to do is pretty much in the for loop:

        for child in children:
            stack.push(child[0])
            parentMap[child] = parent #this line was added
    

    Later on, when you found your target, you can get the path from the source to the target (pseudo code):

    curr = target
    while (curr != None):
      print curr
      curr = parentMap[curr]
    

    Note that the order will be reversed, it can be solved by pushing all elements to a stack and then print.

    I once answered a similar (though not identical IMO) question regarding finding the actual path in BFS in this thread

    Another solution is to use a recursive version of DFS rather then iterative+stack, and once a target is found, print all current nodes in the recursion back up - but this solution requires a redesign of the algorithm to a recursive one.


    P.S. Note that DFS might fail to find a path to the target (even if maintaining a visited set) if the graph contains an infinite branch.
    If you want a complete (always finds a solution if one exists) and optimal (finds shortest path) algorithm - you might want to use BFS or Iterative Deepening DFS or even A* Algorithm if you have some heuristic function

    0 讨论(0)
  • 2021-01-30 09:52

    I just implemented something similar in PHP.

    The basic idea behind follows as: Why should I maintain another stack, when there is the call stack, which in every point of the execution reflects the path taken from the entry point. When the algorithm reaches the goal, you simply need to travel back on the current call stack, which results in reading the path taken in backwards. Here is the modified algorithm. Note the return immediately sections.

    /**
     * Depth-first path
     * 
     * @param Node $node        Currently evaluated node of the graph
     * @param Node $goal        The node we want to find
     *
     * @return The path as an array of Nodes, or false if there was no mach.
     */
    function depthFirstPath (Node $node, Node $goal)
    {
        // mark node as visited
        $node->visited = true;
    
        // If the goal is found, return immediately
        if ($node == $goal) {
            return array($node);
        }
    
        foreach ($node->outgoing as $edge) {
    
            // We inspect the neighbours which are not yet visited
            if (!$edge->outgoing->visited) {
    
                $result = $this->depthFirstPath($edge->outgoing, $goal);
    
                // If the goal is found, return immediately
                if ($result) {
                    // Insert the current node to the beginning of the result set
                    array_unshift($result, $node);
                    return $result;
                }
            }
        }
    
        return false;
    }
    
    0 讨论(0)
提交回复
热议问题