def dfs(starting_puzzle):
    """ Perform a Depth First Search in the graph of the possible
    branches from the initial puzzle, starting with the cells
    with less alternatives. Return a solved puzzle, or None if
    no solution is found. """
    search_stack = [starting_puzzle]
    while search_stack:
        puzzle = search_stack.pop()
        if puzzle.propagate_constraint():
            if puzzle.is_solved():
                return puzzle
            cell = min(puzzle.unset_cells(), key = puzzle.branches)
            for alternative in puzzle.content(cell):
                child = puzzle.copy()
                child.set(cell, alternative)
                search_stack.append(child)
    return None