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
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
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