Пример #1
0
def solver(C, S):
    class ParticionesConjuntoPS(PartialSolution):
        def __init__(self, solucion, sumas_acumuladas):
            self.solucion = solucion
            self.sumas_acumuladas = sumas_acumuladas
            self.n = len(self.solucion)

        def is_solution(self):
            return self.n == len(C)

        def get_solution(self):
            return self.solucion

        def successors(self):
            if self.n < len(C):
                nuevo_numero = C[self.n]
                for i in range(S):
                    if self.sumas_acumuladas[i] + nuevo_numero <= suma_maxima:
                        #TODO HACER COPIA DE LA LISTA
                        nueva_lista = self.sumas_acumuladas[:]
                        nueva_lista[i] += nuevo_numero
                        yield ParticionesConjuntoPS(self.solucion + (i, ),
                                                    nueva_lista)

    suma_maxima = sum(C) / S
    sumas_acumuladas = [0] * S

    initialPS = ParticionesConjuntoPS((), sumas_acumuladas)
    return BacktrackingSolver.solve(initialPS)
Пример #2
0
def sudoku_solver(sudoku):
    class SudokuPS(PartialSolution):
        def __init__(self, sudoku: Sudoku):
            self.s = sudoku

        # Indica si la sol. parcial es ya una solución factible (completa)
        def is_solution(self) -> bool:
            return primera_vacia(self.s) is None

        # Si es sol. factible, la devuelve. Si no lanza excepción
        def get_solution(self) -> Sudoku:
            return self.s

        # Devuelve la lista de sus sol. parciales sucesoras
        def successors(self) -> Iterable["SudokuPS"]:
            vacia = primera_vacia(self.s)
            if vacia is not None:
                f, c = vacia
                for posible in posibles_en(self.s, f, c):
                    nuevo_sudoku = deepcopy(self.s)
                    nuevo_sudoku[f][c] = posible
                    yield SudokuPS(nuevo_sudoku)

    initial_PS = SudokuPS(sudoku)
    return BacktrackingSolver.solve(initial_PS)
Пример #3
0
def conjuntos_solver(C, S):
    class ConjuntoPs(BacktrackingSolver):
        def __init__(self, ds, subc):
            self.ds = ds
            self.n = len(ds)
            self.subc = subc

        def is_solution(self):
            return self.n == len(C)

        def get_solution(self):
            return self.ds

        def successors(self):
            if self.n < len(C):
                nr = C[self.n]
                for i in range(S):
                    if nr + self.subc[i] <= SUMA:
                        subc2 = self.subc[:]
                        subc2[i] += nr
                        yield ConjuntoPs(self.ds + (i, ), subc2)

    SUMA = sum(C) / S
    initialPS = ConjuntoPs((), [0] * S)
    return BacktrackingSolver.solve(initialPS)
Пример #4
0
def hamiltoniancycle_solver(g: UndirectedGraph) -> Solution:
    class HamiltonianCycle(PartialSolution):
        def __init__(self, solution: Tuple, used: Set):
            self.solution = solution
            self.n = len(solution)
            self.used = used

        def is_solution(self) -> bool:
            return self.n == len(g.V) and self.solution[0] in g.succs(
                self.solution[-1])

        def get_solution(self) -> Solution:
            return self.solution

        def successors(self) -> Iterable["PartialSolution"]:
            if self.n < len(g.V):
                for suc in g.succs(self.solution[self.n - 1]):
                    if suc not in self.used:
                        new_used = deepcopy(self.used)
                        new_used.add(suc)
                        yield HamiltonianCycle(self.solution + (suc, ),
                                               new_used)

    vertice = next(iter(g.V))
    usados = set()
    usados.add(vertice)
    initialPS = HamiltonianCycle((vertice, ), usados)
    return BacktrackingSolver.solve(initialPS)
Пример #5
0
def cryptoSolver(palabras: list):
    class CryptoAPS(PartialSolution):
        def __init__(self):
            self.vistas = len(asignaciones.keys())

        def is_solution(self) -> bool:
            return n_letras == self.vistas

        def get_solution(self) -> Solution:
            return dict(asignaciones)

        def successors(self) -> Iterable["PartialSolution"]:
            if n_letras > self.vistas:
                l = letras[self.vistas]
                for i in range(inicio(l, palabras), 10):
                    if i not in numeros:
                        asignaciones[l] = i
                        if factible(asignaciones, matriz_letras):
                            numeros.add(i)
                            yield CryptoAPS()
                            numeros.remove(i)
                        del asignaciones[l]

    numeros = set()
    asignaciones = {}
    matriz_letras, letras = mat_letras(palabras)
    n_letras = len(letras)
    initialPS = CryptoAPS()
    return BacktrackingSolver.solve(initialPS)
Пример #6
0
def camino_suave_solver(v_ini, g, d, k, total_aristas):
    class PartialPS(PartialSolution):
        def __init__(self, ds: list, ar, v_ini):
            self.ds = ds
            self.n = len(ds)
            self.v_ini = v_ini
            self.ultima_ar = ar

        def is_solution(self) -> bool:
            if self.n > 0:

                if g.succs(self.ds[-1]) > 0:
                    return False
                return True

        def get_solution(self) -> Solution:
            return self.ds

        def successors(self) -> Iterable["PartialSolution"]:
            if self.n < len(g.V):
                for v in g.succs(self.v_ini):
                    if self.n == 0:
                        arista_actual = (v_ini, v)
                        ds2 = self.ds[:]
                        ds2.append(v_ini)
                        ds2.append(v)
                        yield PartialPS(ds2, arista_actual, v)
                    else:
                        peso_ultima_arista = d(self.ultima_ar)
                        arista_actual = (self.ds[-1], v)
                        peso_arista_actual = d(self.ds[-1], v)
                        if abs(peso_arista_actual - peso_ultima_arista) <= k:
                            ds2 = self.ds[:]
                            ds2.append(v)
                            yield PartialPS(ds2, arista_actual, v)

    aristas_comprobadas = dict()
    aristas_a_comprobar = dict()
    for arista in g.E:
        aristas_comprobadas[arista] = 0

    for u, v in g.E:

        if g.in_degree(u) == 0:
            aristas_a_comprobar[(u, v)] = 1
        elif g.in_degree(u) > 0 and g.out_degree(u) > 0:
            # si le llegan aristas y tiene sucesor, le añado el valor de sucesor
            aristas_a_comprobar[(u, v)] = g.in_degree(u)
        # elif g.in_degree(u) > 0 and g.out_degree(v) == 0:
        # 	aristas_a_comprobar[(u, v)] = 1

    # print("Comprobadas",aristas_comprobadas)
    # print("A comprobar",aristas_a_comprobar)

    initialPS = PartialPS([], (), v_ini)
    return BacktrackingSolver.solve(initialPS)
Пример #7
0
def domino_solver(f):
    class DominoPS(BacktrackingSolver):
        def __init__(self, ds, fs):
            self.ds = ds
            self.n = len(ds)
            self.fs = fs

        def is_solution(self):
            return self.n == len(f)

        def get_solution(self):
            return self.ds

        def successors(self):
            if self.n < len(f):
                for ficha in self.fs:
                    if self.n == 0:
                        # copia
                        fs2 = self.fs[:]
                        fs2.remove(ficha)
                        yield DominoPS(self.ds + (ficha, ), fs2)
                        # ficha[::-1] da la vuelta a la tupla
                        yield DominoPS(self.ds + (ficha[::-1], ), fs2)
                    else:
                        ultima_ficha = self.ds[-1]
                        # comprobamos que b[i] == a[i]
                        if ultima_ficha[1] == ficha[
                                0]:  # no hay que girar la ficha
                            # copia
                            fs2 = self.fs[:]
                            fs2.remove(ficha)
                            yield DominoPS(self.ds + (ficha, ), fs2)
                        # comprobamos que b[i] == b[i]
                        elif ultima_ficha[1] == ficha[
                                1]:  # si hay que girar la ficha
                            # copia
                            fs2 = self.fs[:]
                            fs2.remove(ficha)
                            yield DominoPS(self.ds + (ficha[::-1], ), fs2)

    initialPS = DominoPS((), f)
    return BacktrackingSolver.solve(initialPS)
Пример #8
0
def sumandos_solver(problema, S):
    class BuscaSumandosPS(PartialSolution):
        def __init__(self, solucion, suma):
            self.solucion = solucion
            self.n = len(self.solucion)
            self.suma = suma

        def is_solution(self):
            return self.n == len(problema) and self.suma == S

        def get_solution(self):
            return self.solucion

        def successors(self):
            if self.n < len(problema):
                for numero in problema[self.n]:
                    if self.suma + numero <= S:
                        yield BuscaSumandosPS(self.solucion + (numero,), self.suma + numero)

    initial_ps = BuscaSumandosPS((), 0)
    return BacktrackingSolver.solve(initial_ps)
Пример #9
0
def grafo_solver(g, vertices_grafo):
    class CicloHM(PartialSolution):
        def __init__(self, ds):
            self.ds = ds
            self.n = len(ds)
            self.vertices = vertices_grafo

        def is_solution(self):
            return self.n == len(g.V) and self.ds[0] in g.succs(self.ds[-1])

        def get_solution(self):
            return self.ds

        def successors(self):
            if self.n < len(g.V):
                for v in g.succs(self.vertices[self.n]):
                    if v not in self.ds:
                        yield CicloHM(self.ds + (v, ))

    initial_ps = CicloHM(())
    return BacktrackingSolver.solve(initial_ps)
Пример #10
0
def sumandos_solver(problema: List[List[int]], S: int) -> Iterable:
    class BuscandoSumandoPS(PartialSolution):
        def __init__(self, sol: Tuple, s: int):
            self.sol = sol
            self.n = len(sol)
            self.s = s

        def is_solution(self) -> bool:
            return self.n == len(problema) and self.s == S

        def get_solution(self) -> Solution:
            return self.sol

        def successors(self) -> Iterable["PartialSolution"]:
            if self.n < len(problema):
                for elem in problema[self.n]:
                    suma = self.s + elem
                    if suma <= S:
                        yield BuscandoSumandoPS(self.sol + (elem, ), suma)

    initialPS = BuscandoSumandoPS((), 0)
    return BacktrackingSolver.solve(initialPS)
Пример #11
0
def sumandos_solver(S, lista_numeros):
    class BuscaSumandosPS(PartialSolution):
        def __init__(self, solution, quedan):
            self.solution = solution
            self.quedan = quedan
            self.n = len(solution)

        def is_solution(self) -> bool:
            return self.quedan == S

        def get_solution(self) -> Solution:
            return self.solution

        def successors(self) -> Iterable["KnapsackPS"]:
            for item in lista_numeros[self.n]:
                if item + self.suma <= S:
                    yield BuscaSumandosPS(self.solution + (item, ),
                                          self.quedan + item)

    initialPS = BuscaSumandosPS(
        (), 0)  # IMPLEMENTAR: Añade los parámetros que tú consideres

    return BacktrackingSolver.solve(initialPS)
Пример #12
0
def lista_solver(C, S):
    class ListaPs(PartialSolution):
        def __init__(self, ds, sumaLocal):
            self.ds = ds
            self.n = len(ds)
            self.sumaLocal = sumaLocal

        def is_solution(self):
            return self.n == len(C) and self.sumaLocal == S

        def get_solution(self):
            return self.ds

        def successors(self):
            if self.n < len(C):
                for i in C[self.n]:
                    if i + self.sumaLocal <= S:
                        yield ListaPs(self.ds + [
                            i,
                        ], self.sumaLocal + i)

    initialPS = ListaPs([], 0)
    return BacktrackingSolver.solve(initialPS)
Пример #13
0
def crypto_solver(words):
    #print(words)
    class CryptoAPS(PartialSolution):

        def __init__(
                self, dict, char_index, word_index, digits_left, sum, current_letter
        ):
            self.dict = dict
            self.n = len(dict)
            self.char_index = char_index
            self.word_index = word_index
            self.digits_left = digits_left
            self.n_words = len(words)
            self.n_chars = len(words[-1])
            self.sum = sum
            self.current_letter = current_letter

        def is_solution(self) -> bool:
            if self.n != n_letters(words):
                return False
            if self.dict[words[-1][0]] == 0:
                return False
            hidden = []
            for word in words:
                number = 0
                for i in range(1, len(word)+1):
                    number += self.dict[word[-i]] * 10 ** (i - 1)
                #print(number)
                hidden.append(number)

            return sum(hidden[:-1]) == hidden[-1]


        def get_solution(self) -> Solution:
            return self.dict

        def feasible(self, digit: int, run_call: bool) -> bool:
            #print("sum, digit, index, word index", self.sum, digit, self.char_index, self.word_index)
            known_col = self.word_index < self.n_words - 1
            extra_value = 0

            add_digit = 0
            if not run_call:
                add_digit = digit

            for i in range(self.word_index + 1, self.n_words):
                word = words[i]
                is_there = self.char_index <= len(word)
                known = not is_there or word[-self.char_index] in self.dict.keys()
                #print(known)
                if not known:
                    known_col = False
                    break
                if is_there and i < self.n_words - 1:
                    extra_value += self.dict[word[-self.char_index]]

            if known_col:
                #print("Esta ", words[-1][-self.char_index], "en dict:",
                #      words[-1][-self.char_index] in self.dict.keys())
                part = (self.sum + (add_digit + extra_value) * 10 ** (self.char_index - 1))
                left = (part // (10 ** (self.char_index - 1))) % 10
                letter_o = words[-1][-self.char_index]
                right = self.dict[letter_o]
                coherent = left == right
                #print(
                #   "Am ", self.current_letter, ", in (", self.word_index, self.char_index, "letters below value",
                #    extra_value, "total sum is ", self.sum, "plus mine ,",digit,"."
                #    ". Part is ", part, ". That makes ",right, ", which is value of ", letter_o,
                #    "but actually ", left, coherent)
            #print("char", self.char_index)
            right_c = (self.sum // (10 ** (self.char_index - 1))) % 10

            return  not (digit == 0 and self.char_index == len(words[self.word_index])) and (
                    self.word_index < self.n_words - 1 and (
                    not known_col or
                    known_col and coherent) or
                    not self.word_index < self.n_words - 1 and digit == (self.sum // (10 ** (self.char_index - 1))) % 10
            )

        def next_letter(self) -> string:
            if self.word_index == self.n_words - 1:
                self.word_index = 0
                self.char_index += 1
            else:
                self.word_index += 1
            if self.char_index <= len(words[self.word_index]):
                return words[self.word_index][-self.char_index]
            else:
                return None

        def successors(self) -> Iterable["CryptoAPS"]:
            last = self.word_index == self.n_words and self.char_index == len(words[-1])
            #print("Lo pillo en", self.word_index, self.char_index, self.current_letter)
            right_path = True
            default = True
            #print("FUERA: ", self.current_letter)

            while self.current_letter is None or self.current_letter in self.dict.keys():
                right_path = default or self.current_letter is None or self.feasible(self.dict[self.current_letter], True)
                if not right_path:
                    break
                #print(self.current_letter, "llamando a next,", self.char_index)
                self.current_letter = self.next_letter()
                #print(self.current_letter, "después de next,", self.char_index)
                #print("E none?", self.current_letter is None)
                default = False
                if self.word_index != self.n_words - 1 and self.current_letter in self.dict.keys():
                    #print("Esto sucede en letra", self.current_letter)
                    self.sum += self.dict[self.current_letter] * 10 ** (self.char_index - 1)
            #print(self.current_letter)
            #print(self.word_index, self.char_index)

            #print(self.current_letter)
            if right_path:
                for digit in self.digits_left:
                    #print("try " + self.current_letter + " = " + str(digit))
                    if self.feasible(digit, False):
                        sum = self.sum
                        #print("feasible")
                        copy_dict = deepcopy(self.dict)
                        copy_dict[self.current_letter] = digit
                        if self.word_index != self.n_words - 1:
                            sum += digit * 10 ** (self.char_index - 1)
                        digits_left = set(number for number in self.digits_left if number != digit)
                        #print(copy_dict)
                        #print(self.n, n_letters(words))
                        if self.n != n_letters(words) or last:
                            yield CryptoAPS(
                                copy_dict, self.char_index, self.word_index, digits_left, sum, self.current_letter
                            )
            #print("Lo dejo en", self.word_index, self.char_index, self.current_letter)


    initial_pc = CryptoAPS(
        {}, 1, 0, set(n for n in range(10)), 0, words[0][-1]
    )
    # dict, char_index, word_index, digits_left, sum, current_letter
    return BacktrackingSolver.solve(initial_pc)
Пример #14
0
def camino_suave_solver(v_ini, g, d, k, total_aristas):
    class PartialPS(PartialSolution):
        def __init__(self, ds, ar: list, ultima_arista, contador):
            self.ds = ds
            self.n = len(ds)
            self.ar = ar
            self.ultima_arista = ultima_arista
            self.contador = contador

        def is_solution(self) -> bool:
            for polla in aristas_a_comprobar.items():
                arista = polla[0]
                valor = polla[1]
                if aristas_comprobadas[arista] != valor:
                    return False
            return True

        def get_solution(self) -> Solution:
            return self.ds

        def successors(self) -> Iterable["PartialSolution"]:
            # if self.n  < len(g.E):
            for arista in self.ar:
                if self.n == 0:
                    for v in g.succs(v_ini):
                        arista_actual = (v_ini, v)
                        ar2 = self.ar.copy()
                        ar2.remove(arista_actual)
                        aristas_comprobadas[arista_actual] = 1
                        yield PartialPS(self.ds + (v_ini, ) + (v, ), ar2,
                                        arista_actual, self.contador + 1)
                else:

                    # comprobar si la ultima arista tiene camino con la arista actual
                    if self.ultima_arista[1] == arista[0]:
                        peso_arista_actual = d(arista)
                        peso_arista_ultima = d(self.ultima_arista)
                        # comprobamos que realmente sea un camino valido: <= k
                        if abs(peso_arista_actual - peso_arista_ultima) <= k:
                            ar2 = self.ar.copy()
                            # ar2.remove(arista)

                            arista_actual = (self.ultima_arista[1], arista[1])
                            yield PartialPS(self.ds + (arista[1], ), ar2,
                                            arista_actual, self.contador + 1)

                        else:
                            # resetear aristas_comprobadas
                            for arista in g.E:
                                aristas_comprobadas[arista] = 0
                            break
                            # borrar el la arista en la cual estoy e irme a la arista anterior
                            # ar2 = self.ar.copy()
                            # ar2.remove(arista)
                            # self.ar.remove(arista)
                            # yield PartialPS(self.ds, ar2, self.ultima_arista, self.contador + 1)
                    else:
                        # no hay camino para esta arista, borramos la 1a arista de todas las aristas
                        ar2 = self.ar.copy()
                        ar2.remove(arista)
                        aristas_comprobadas[arista] += 1
                        # self.ar.remove(arista)
                        # yield PartialPS(self.ds, ar2, self.ultima_arista, self.contador + 1)
                        # self.contador += 1

    aristas_comprobadas = dict()
    aristas_a_comprobar = dict()
    for arista in g.E:
        aristas_comprobadas[arista] = 0

    for u, v in g.E:

        if g.in_degree(u) == 0:
            aristas_a_comprobar[(u, v)] = 1
        elif g.in_degree(u) > 0 and g.out_degree(u) > 0:
            # si le llegan aristas y tiene sucesor, le añado el valor de sucesor
            aristas_a_comprobar[(u, v)] = g.in_degree(u)

    initialPS = PartialPS((), list(g.E), (), 0)
    return BacktrackingSolver.solve(initialPS)
Пример #15
0
            new_sudoku[f][c] = item
            yield SudokuPS(new_sudoku)


# PROGRAMA PRINCIPAL -------------------------------------------------------
if __name__ == "__main__":
    init = time.time()
    # m_sudoku = [[0, 0, 0, 3, 1, 6, 0, 5, 9], [0, 0, 6, 0, 0, 0, 8, 0, 7], [0, 0, 0, 0, 0, 0, 2, 0, 0],
    #             [0, 5, 0, 0, 3, 0, 0, 9, 0], [7, 9, 0, 6, 0, 2, 0, 1, 8], [0, 1, 0, 0, 8, 0, 0, 4, 0],
    #             [0, 0, 8, 0, 0, 0, 0, 0, 0], [3, 0, 9, 0, 0, 0, 6, 0, 0], [5, 6, 0, 8, 4, 7, 0, 0, 0]]

    # El sudoku más difícil del mundo
    m_sudoku = [[8, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 6, 0, 0, 0, 0, 0],
                [0, 7, 0, 0, 9, 0, 2, 0, 0], [0, 5, 0, 0, 0, 7, 0, 0, 0],
                [0, 0, 0, 0, 4, 5, 7, 0, 0], [0, 0, 0, 1, 0, 0, 0, 3, 0],
                [0, 0, 1, 0, 0, 0, 0, 6, 8], [0, 0, 8, 5, 0, 0, 0, 1, 0],
                [0, 9, 0, 0, 0, 0, 4, 0, 0]]

    print("Original:")
    pretty_print(m_sudoku)
    print("\nSoluciones:")
    # Mostrar todas las soluciones
    # IMPLEMENTAR utilizando SudokuPS y BacktrackingSolver
    for solution in BacktrackingSolver.solve(SudokuPS(m_sudoku)):
        pretty_print(solution)
        print("Solution found at: ", time.time() - init, "seconds.")
    print(
        "<TERMINDADO>"
    )  # Espera a ver este mensaje para saber que el programa ha terminado
    print("Program ended asudoku_easy.pyt: ", time.time() - init, "seconds.")
Пример #16
0
        for num in posibles_en(self.s, f, c):
            copia_sudoku = deepcopy(self.s)
            copia_sudoku[f][c] = num
            yield SudokuPS(copia_sudoku)


# PROGRAMA PRINCIPAL -------------------------------------------------------
if __name__ == "__main__":
    #m_sudoku = [[0, 0, 0, 3, 1, 6, 0, 5, 9], [0, 0, 6, 0, 0, 0, 8, 0, 7], [0, 0, 0, 0, 0, 0, 2, 0, 0],
    #           [0, 5, 0, 0, 3, 0, 0, 9, 0], [7, 9, 0, 6, 0, 2, 0, 1, 8], [0, 1, 0, 0, 8, 0, 0, 4, 0],
    #           [0, 0, 8, 0, 0, 0, 0, 0, 0], [3, 0, 9, 0, 0, 0, 6, 0, 0], [5, 6, 0, 8, 4, 7, 0, 0, 0]]

    # El sudoku más difícil del mundo
    m_sudoku = [[8, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 6, 0, 0, 0, 0, 0],
                [0, 7, 0, 0, 9, 0, 2, 0, 0], [0, 5, 0, 0, 0, 7, 0, 0, 0],
                [0, 0, 0, 0, 4, 5, 7, 0, 0], [0, 0, 0, 1, 0, 0, 0, 3, 0],
                [0, 0, 1, 0, 0, 0, 0, 6, 8], [0, 0, 8, 5, 0, 0, 0, 1, 0],
                [0, 9, 0, 0, 0, 0, 4, 0, 0]]

    print("Original:")
    pretty_print(m_sudoku)
    print("\nSoluciones:")
    # Mostrar todas las soluciones
    # IMPLEMENTAR utilizando SudokuPS y BacktrackingSolver
    initial_PS = SudokuPS(m_sudoku)
    for solution in BacktrackingSolver.solve(initial_PS):
        pretty_print(solution)

    print(
        "<TERMINDADO>"
    )  # Espera a ver este mensaje para saber que el programa ha terminado
Пример #17
0
def distribucion_solve(almacenA, almacenB, fabricas, costeA, costeB,
                       componentes):
    class DistribucionPS(PartialSolution):
        def __init__(self, coste, solucion, almacenA, almacenB, fabricas,
                     costeA, costeB, componentes):
            self.coste = coste
            self.solucion = solucion
            self.almacenA = almacenA
            self.almacenB = almacenB
            self.fabricas = fabricas
            self.costeA = costeA
            self.costeB = costeB
            self.componentes = componentes

        def is_solution(self) -> bool:
            return len(self.solucion) == self.fabricas

        def get_solution(
                self) -> Solution:  #Tuple[int, List[Tuple[int, int]]]:
            return (self.coste, self.solucion)

        def successors(self) -> Iterable["DistribucionPS"]:
            if not self.is_solution():
                fabrica = len(self.solucion)
                if self.componentes[fabrica] < self.almacenA:
                    if self.componentes[fabrica] < self.almacenB:
                        n_comp = 0
                        while n_comp <= componentes[fabrica]:
                            coste_transporte = (
                                self.costeA[fabrica] *
                                n_comp) + self.costeB[fabrica] * (
                                    self.componentes[fabrica] - n_comp)
                            s = self.solucion[:]
                            s.append(
                                (n_comp, self.componentes[fabrica] - n_comp))
                            yield DistribucionPS(
                                self.coste + coste_transporte, s,
                                self.almacenA - n_comp, self.almacenB -
                                (self.componentes[fabrica] - n_comp),
                                self.fabricas, self.costeA, self.costeB,
                                self.componentes)
                            n_comp += 1

                    else:
                        n_comp = 0
                        #         for hasta almacenB
                        while n_comp <= self.almacenB:
                            coste_transporte = (self.costeA[fabrica] * (self.componentes[fabrica]-(self.almacenB-n_comp))) + \
                                               self.costeB[fabrica] * (self.almacenB-n_comp)
                            s = self.solucion[:]
                            s.append(((self.componentes[fabrica] -
                                       (self.almacenB - n_comp),
                                       (self.almacenB - n_comp))))
                            yield DistribucionPS(
                                self.coste + coste_transporte, s,
                                self.almacenA - (self.componentes[fabrica] -
                                                 (self.almacenB - n_comp)),
                                self.almacenB - (self.almacenB - n_comp),
                                self.fabricas, self.costeA, self.costeB,
                                self.componentes)
                            n_comp += 1
                else:
                    n_comp = 0
                    #     for hasta almacenA
                    while n_comp <= self.almacenA:
                        coste_transporte = (self.costeA[fabrica] * (self.almacenA-n_comp)) + \
                                           self.costeB[fabrica] * (self.componentes[fabrica]-(self.almacenA-n_comp))
                        s = self.solucion[:]
                        s.append(((self.almacenA - n_comp),
                                  (self.componentes[fabrica] -
                                   (self.almacenA - n_comp))))
                        yield DistribucionPS(
                            self.coste + coste_transporte, s,
                            self.almacenA - (self.almacenA - n_comp),
                            self.almacenB - (self.componentes[fabrica] -
                                             (self.almacenB - n_comp)),
                            self.fabricas, self.costeA, self.costeB,
                            self.componentes)
                        n_comp += 1

    initialPS = DistribucionPS(0, [], almacenA, almacenB, fabricas, costeA,
                               costeB, componentes)
    print("hi")
    return BacktrackingSolver.solve(initialPS)