示例#1
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    
    # We define a queue == breadth-first search
    queue = QueueFrontier()
    exploredSet = list()

    # We're going to look neighbors 
    node = Node(source, None, None)
    exploredSet.append(source)
    neighbors = neighbors_for_person(source)
    
    # If doesn't has any neighbor, return None (there are people that has done just one movie of 1 actor)
    if len(neighbors) == 0:
        return None
    
    # For each neighbor, add to the queue each possible action (walk through the movie)
    for i in neighbors:
        node = Node(state = i[1], parent = None, action = i[0])
        queue.add(node)
    # Check if we found the target
    if queue.contains_state(target):
        node = queue.search_state(target)
        return [(node.getAction(), target)]

    # took out an element from the queue and walk through the neighboors
    while not queue.empty():

        parent = queue.remove() 

        """ This is not necesary, because i found an eficient implementation checking if we reached the target when
        we add a node, and not when we remove it...

        if parent.getState() == target:
            # Once we have the target, go backwards. FIFO will be useful to do the path till the target
            result = StackFrontier()
            # Add the target element and go backward till the beginning through the parents
            result.add(parent)
            node = parent.getParent()
            while node != None:
                result.add(node)
                node = node.getParent()
            # build the return list in the correct order taking out every stack element
            r = list()
            while not result.empty():
                node = result.remove()
                movie = node.getAction()
                person = node.getState()
                r.append([movie, person])
            return r
        """
        
        # Add the node to the explore dataset because we don't want to walk through the same way that we came
        exploredSet.append(parent.getState())

        # expand the node and find neighbors
        neighbors = neighbors_for_person(parent.getState())  # remember state == person

        # For each neighbor we have the name of the neighbor i[1] and the movie i[0] shared with the parent of the neighbor
        for i in neighbors:
            node = Node(state=i[1], parent=parent, action=i[0]) #  action == movies

            # If we have been in this neighbor before (this person), continue and don't expand this node again
            if queue.contains_state(node.getState()) or node.getState() in exploredSet:
                continue
            queue.add(node)

            # Check if this node has the target
            if node.getState() == target:
                # Once we have the target, go backwards. FIFO will be useful for this
                result = StackFrontier()
                # add the target element and go backward till the beginning through the parents
                result.add(node)
                node = node.getParent()
                while node != None:
                    result.add(node)
                    node = node.getParent()
                # build the return list in the correct order taking out every stack element
                r = list()
                while not result.empty():
                    node = result.remove()
                    movie = node.getAction()
                    person = node.getState()
                    r.append([movie, person])
                return r
        

    # raise NotImplementedError
    return None