Beispiel #1
0
def bfs(G, s):
    """
    Breadth-first search of a graph.

    Breadth-first search is one of the simplest algorithms for searching a graph. It
     is also the archetype for many important graph algorithms.

    BFS is so named because it gradually expands the frontier between discovered
     and undiscovered vertices uniformly across the breadth of the frontier. That
     is it will discover all vertices at the nearest distance before discovering any
     vertices on further distances, as opposed to depth-first search.

    To keep track of the progress BFS colors each vertex white, gray or black.
     All vertices start out white. A vertex is discovered the first time it is
     encountered during the search at which time it becomes nonwhite. Gray vertices
     represent the frontier between discovered and undiscovered vertices.

    When vertex is discovered BFS saves a pointer to the predecessor (or parent) vertex
     from which it was discovered, and the distance from the source vertex. BFS
     correctly computes the shortest path, or a minimum amount of edges it took to
     reach the vertex from the starting vertex in an unweighted graph. If we follow
     parent records in a breadth-first tree after BFS was finished all the way to
     the starting vertex we'll get the shortest route it would take to reach the
     destination vertex.

    Complexity: O(V+E). `V` devoted to queue operations for each vertex and `E` is
     for the total time spent on scanning adjacent vertices.
    :param Graph G: Adjacency list graph representation
    :param Vertex s: Pointer to the starting vertex
    :return None: Vertices are updated
    """
    n = len(G.V)  # Total number of vertices in a graph

    for u in G.V:
        if u is not s:
            u.color = WHITE
            u.d = inf
            u.p = None
    s.color = GRAY
    s.d = 0
    s.p = None
    Q = Queue(n)
    enqueue(Q, s)
    while Q.length != 0:
        u = dequeue(Q)
        for v in G.Adj(u):
            if v.color is WHITE:
                v.color = GRAY
                v.d = u.d + 1
                v.p = u
                enqueue(Q, v)
        u.color = BLACK
Beispiel #2
0
def solution(M):
    """
    Snake and Ladders minimum moves solver.

    Every throw of dice generates one move possibility. Together they form a graph of all
     possible moves and associated distance, or number of preceding moves required to
     reach that cell. Using simple breadth-first search algorithm we'll be able to find
     the shortest distance to the last cell.

    Complexity: O(V+E) where `V` is number of cells and `E` is number of possible "jumps"
    :param list[int] M: List board representation
    :return int: Minimum amount of dice throws required to reach the final cell
    """
    from basic_data_structures.fifo import Queue, enqueue, dequeue, next as peek

    visited = [False] * (len(M) + 1)  # Map of visited cells
    visited[0] = True
    q = Queue(len(M))
    move = Move(0, 0)  # Generate first move
    enqueue(q, move)
    while q.length > 0:
        move = peek(q)
        if move.cell == len(M) - 1:
            break  # Reached the end, `move` is the last cell
        dequeue(q)
        for dice in range(1, 7):  # Try all the dice throws
            next_i = move.cell + dice
            if next_i < len(M):
                if visited[next_i] is False:
                    visited[next_i] = True
                    if M[next_i] == 0:
                        enqueue(q, Move(next_i, move.dist + 1))
                    else:
                        enqueue(q, Move(M[next_i], move.dist + 1))
    return move.dist
Beispiel #3
0
def build(D, s, t):
    """
    Words production sequence path builder using BFS algorithm.

    This BFS sub-routine connects vertices in a graph, writes parent pointers and
     distance from the source string.

    Complexity: O(n+nm) from BFS, where `n` is the number of words in the dictionary and
     `m` is the length of words used. Time devoted to construction of candidate strings
     is constant bound to the alphabet size. The number of edges in the worst case is
     `n^2`.
    :param set D: Dictionary (set) of words
    :param str s: Source string
    :param str t: Target string
    :return Vertex|None: Vertex containing target string (if found)
    """
    n = len(D)
    Q = Queue(n)
    D.remove(s)  # Remove used word from a dictionary
    enqueue(Q, Vertex(s, 0))
    while Q.length > 0:
        v = peek(Q)
        if v.candidate_string == t:
            return v  # Target is found
        cs = list(v.candidate_string)  # Converting to list, strings are immutable
        # Try all possible permutations of a candidate string
        for i in range(0, len(cs)):
            for c in ALPHABET:
                cs[i] = c
                cs_as_str = "".join(cs)
                if cs_as_str in D:
                    D.remove(cs_as_str)
                    enqueue(Q, Vertex(cs_as_str, v.distance + 1, v))
            cs[i] = v.candidate_string[i]
        dequeue(Q)
    return None