Programación IV. Guía No. 11 1 Facultad: Ingeniería Escuela: Computación Asignatura: Programación IV Tema: Algoritmos Backtracking. Objetivos Específicos Comprender el funcionamiento de un Algoritmo Backtracking. Identificar problemas que pueden resolverse con Algoritmos Bactracking. Codificar algoritmos backtracking en C#. Materiales y Equipo Guía Número 11. Computadora con programa Microsoft Visual C#. NET. Introducción Teórica Hay problemas para los que no se conoce un algoritmo para su resolución o al menos, no cuentan con un algoritmo eficiente para calcular su solución. En estos casos, la única posibilidad es una exploración directa de todas las posibilidades. La técnica Backtracking es un método de búsqueda de soluciones exhaustiva sobre grafos dirigidos acíclicos, el cual se acelera mediante poda de ramas poco prometedoras. Es decir: Se representan todas las posibilidades en un árbol. Se resuelve buscando la solución por el árbol (de una determinada manera). Hay zonas que se evitan por no contener soluciones (poda). La solución del problema se representa en una lista ordenada (X1, X2,…, Xn) (no llenando necesariamente todas las componentes). Cada Xi se escoge de un conjunto de candidatos. A cada lista se le llama estado. Se trata de buscar estados solución del problema. 2 Programación IV. Guía No. 11 Tiene condiciones de parada: a) cuando se alcanza un estado solución. b) cuando se alcanzan todos los estados solución. En su forma básica, la idea de backtracking se asemeja a un recorrido en profundidad dentro de un grafo dirigido. El grafo en cuestión suele ser un árbol, o por lo menos no contiene ciclos. Sea cual sea su estructura, existe sólo implícitamente. El objetivo del recorrido es encontrar soluciones para algún problema. El recorrido tiene éxito si, procediendo de esta forma, se puede definir por completo una solución. En este caso el algoritmo puede bien detenerse (si lo único que se necesita es una solución del problema) o bien seguir buscando soluciones alternativas (si deseamos examinarlas todas). Por otra parte, el recorrido no tiene éxito si en alguna etapa la solución parcial construida hasta el momento no se puede completar. En tal caso, el recorrido vuelve atrás exactamente igual que en un recorrido en profundidad, eliminando sobre la marcha los elementos que se hubieran añadido en cada fase. Cuando vuelve a un nodo que tiene uno o más vecinos sin explorar, prosigue el recorrido de una solución. Los problemas que deben satisfacer un determinado tipo de restricciones son problemas completos, donde el orden de los elementos de la solución no importa. Estos problemas consisten en un conjunto (o lista) de variables a la que a cada una se le debe asignar un valor sujeto a las restricciones del problema. La técnica va creando todas las posibles combinaciones de elementos para obtener una solución. Su principal virtud es que en la mayoría de las implementaciones se puede evitar combinaciones, estableciendo funciones de acotación (o poda) reduciendo el tiempo de ejecución. La técnica backtracking (vuelta atrás) está muy relacionada con la búsqueda binaria. Diseño e implementación Backtracking. Esencialmente, la idea es encontrar la mejor combinación posible en un momento determinado, por eso, se dice que este tipo de algoritmo es una búsqueda en profundidad. Normalmente, se suele implementar este tipo de algoritmos como un procedimiento recursivo. La diferencia con la búsqueda en profundidad es que se suelen diseñar funciones de cota, de forma que no se generen algunos estados si no van a conducir a ninguna solución, o a una Programación IV. Guía No. 11 3 solución peor de la que ya se tiene. De esta forma se ahorra espacio en memoria y tiempo de ejecución. Al diseñar un algoritmo backtraking debemos considerar los siguientes elementos: a. Representación de la solución en una lista ordenada (X1, X2,…, Xn). b. Una función objetivo para determinar si la lista a analizar es una solución. c. Unas restricciones a los candidatos para rellenar la lista: Implícitas del problema. Valores que puede tomar cada valor Xi. Explícitas o externas al problema. Por ejemplo, problema de la mochila, el peso no debe superar la capacidad de la mochila. d. Una función de poda para eliminar partes del árbol de búsqueda e. Organización del problema en un árbol de búsqueda. f. Construir la solución al problema en distintas etapas. g. En cada paso se elige un candidato y se añade a la solución, y se avanza en la solución parcial. h. Si no es posible continuar en la construcción hacia una solución completa, se abandona ésta y la última componente se cambia por otro valor. i. Si no quedan más valores por probar, se retrocede al candidato anterior, se desecha, y se selecciona otro candidato. Para diseñar un algoritmo con la técnica backtracking, debemos seguir los siguientes pasos: 1. Buscar una representación del tipo (X1, X2,…, Xn) para las soluciones del problema. 2. Identificar las restricciones implícitas y explícitas del problema. 3. Establecer la organización del árbol que define los diferentes estados en los que se encuentra una (sub)solución. 4. Definir una función solución para determinar si una lista ordenada es solución. 5. Definir una función de poda Bk (X1, X2,…, Xk) para eliminar ramas del árbol que puedan derivar en soluciones poco deseables o inadecuadas. 6. Aplicar la estructura genérica de un algoritmo backtracking. Estructura genérica para un algoritmo backtracking. Solucion [i] ∈ Si para i = 1, 2,..., n funcion BACKTRACKING_REC (k, solucion [n]) para j ∈ Si 4 Programación IV. Guía No. 11 si (PODA (k, j, solucion) == true) hacer sol [k] = j si (TEST_SOL (solucion) == true) hacer devolver solucion si (k < n) BACKTRACKING_REC (k+1, solucion [n]) La eficiencia en un algoritmo backtracking suele ser de tipo exponencial an. La eficiencia depende de: la ramificación del árbol. del tiempo de ejecución de la función solución. del tiempo de ejecución de la función poda. del ahorro de utilizar la poda. Las buenas funciones de poda no son muy eficientes. Entre los problemas típicos que se pueden resolver fácilmente con las técnicas de vuelta atrás tenemos: la vuelta del caballo, sudoku, laberintos, sopa de letras, problema de las parejas, formación de una palabra con “n” cubos, problema del dominó, problema del reparto del botín, coloreado de grafos, problema del viajante sobre grafos dirigidos; entre otros. Procedimiento Ejemplo 1. Problema del Sudoku. El Sudoku es un rompecabezas matemático de colocación que se popularizó en Japón en 1986 y se dio a conocer en el ámbito internacional en 2005. El objetivo es rellenar una cuadrícula de 9×9 celdas dividida en subcuadrículas de 3×3 con las cifras del 1 al 9 partiendo de algunos números ya dispuestos en algunas de las celdas. No se debe repetir ninguna cifra en una misma fila, columna o subcuadrícula. Visualización de Sudoku: Programación IV. Guía No. 11 5 A continuación, implementaremos el algoritmo backtracking para resolver el problema del Sudoku en un proyecto de Visual C#. 1. Crear un proyecto de consola, se sugiere llamarlo “Algoritmo Backtracking”. 2. Cambiamos el nombre del “Program.cs” a “Sudoku.cs”. 3. Agregar el siguiente código a la clase “Sudoku” 6 Programación IV. Guía No. 11 Programación IV. Guía No. 11 7 8 Programación IV. Guía No. 11 Análisis de resultados Ejercicio 1. Realice un programa en C# para implementar la solución al problema del Sudoku en una interfaz gráfica de formulario (Windows Forms). La aplicación debe permitir realizar las siguientes operaciones: Generar nuevos juegos (distintos cada vez que se seleccione esta opción) de manera automática. Generar nuevos juegos (cargar un tablero en blanco, para que el usuario coloque la condición inicial del juego). Comprobar solución (debe verificarse la solución realizada por el usuario). Resolver juego actual. En las imágenes se muestran ejemplos de cómo podría lucir su aplicación: Programación IV. Guía No. 11 9 Investigación Complementaria Para la siguiente semana: Investigue el problema de la vuelta del caballo (variante del juego de ajedrez), y realice su solución con un algoritmo backtracking. La implementación debe realizarse con Visual C# en una interfaz gráfica de formulario (Windows Forms). La solución debe permitir realizar las siguientes acciones: Permitir al usuario indicar el tamaño del tablero. Permitir al usuario colocar el caballo en la posición inicial que desee. Los movimientos del caballo deben observarse en pantalla, es decir, que debe quedar en pantalla, las distintas posiciones que ya ocupó el caballo (es decir, que debe existir una simulación de los movimientos del caballo. El programa indicará si existe solución o no existe solución. 10 Programación IV. Guía No. 11 Hoja de cotejo: Guía 11: Algoritmos Backtracking. Alumno: Máquina No: Docente: GL: 11 Fecha: EVALUACIÓN % CONOCIMIENTO Del 20 al 30% APLICACIÓN DEL CONOCIMIENTO Del 40% al 60% ACTITUD Del 15% al 30% TOTAL 100% 1-4 5-7 8-10 Conocimiento deficiente de los fundamentos teóricos Conocimiento y explicación incompleta de los fundamentos teóricos Conocimiento completo y explicación clara de los fundamentos teóricos No tiene actitud proactiva. Actitud propositiva y con propuestas no aplicables al contenido de la guía. Tiene actitud proactiva y sus propuestas son concretas. Nota