Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad

Tema 6 Vuelta Atrás , Apuntes de Ingeniería Infórmatica

Asignatura: Análisis y Diseño de Algoritmos, Profesor: , Carrera: Grado en Ingeniería Informática, Universidad: UMA

Tipo: Apuntes

2014/2015

Subido el 21/01/2015

estudiantemodel
estudiantemodel 🇪🇸

4.8

(5)

1 documento

1 / 45

Toggle sidebar

Documentos relacionados


Vista previa parcial del texto

¡Descarga Tema 6 Vuelta Atrás y más Apuntes en PDF de Ingeniería Infórmatica solo en Docsity! Tema 6 Vuelta Atrás • Introducción • Búsqueda por fuerza bruta • Restricciones implícitas y explícitas • Vuelta Atrás y recursión • Esquema de resolución • Aplicaciones • Ejemplos Introducción Divide y Vencerás Algoritmos Voraces Programación Dinámica Vuelta Atrás Análisis y Diseño de Algoritmos Introducción Divide y Vencerás Algoritmos Voraces Programación Dinámica Vuelta Atrás Análisis y Diseño de Algoritmos Principio de óptimo Introducción Divide y Vencerás Algoritmos Voraces Programación Dinámica Vuelta Atrás Análisis y Diseño de Algoritmos Búsqueda exhaustiva y sistemática Introducción: concepto "Vuelta atrás"(Backtracking) es una estrategia para encontrar soluciones a problemas que safisfacen restricciones. El término "backtrack" fue acuñado por primera vez por el matemático estadounidense Derrick Henry Lehmer (1905-1991) en los años 1950s. Búsqueda por fuerza bruta ¿ Cuándo se usa? 1. Cuando el tamaño del problema es limitado; 2. Cuando hay heurísticas que pueden conducirnos a la solución de forma más temprana (o sea, que aceleran la búsqueda por ejemplo guiando el algoritmo hacia las regiones más prometedoras – donde presumibleente se encuentre una solución - del espacio de búsqueda). Cuando la eficiencia no es importante. Ventajas: 1. Es muy fácil de implementar. 2. Siempre “garantiza” encontrar la solución (óptimo si es un problema de optimización) si existe al menos una solución. Desventajas: • Su ineficiencia lo cual hace esa técnica impracticable para muchísimos problemas ya que el coste computacional es proporcional al número de candidatos a ser solución. El diseño Vuelta Atrás (VA) • es un refinamiento de la búsqueda por fuerza bruta y proporciona una metodología para hacer esta búsqueda segura y eficiente; • proporciona una manera sistemática de generar todas las posibles soluciones siempre que dichas soluciones sean susceptibles de resolverse en etapas. • se podría decir que es una búsqueda por fuerza bruta en la cual se reduce de manera significativa el número de candidatos a ser solución por lo que el coste computacional es reducido considerablemente. Vuelta atrás (VA) El diseño Vuelta Atrás (VA) se usa generalmente en problemas que deben satisfacer un determinado tipo de restricciones. • Los problemas suelen ser 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 las 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. La diferencia con la Fuerza bruta radica en que se pueden evitar muchas combinaciones, haciendo uso de las restricciones. Vuelta atrás (VA) ¿Se puede expresar una solución como una n-tupla de valores (x1,x2,...xn)? Si la respuesta es sí, entonces la VA tiene sentido. VA: restricciones En los algoritmos de VA se diferencian dos tipos de restricciones • Explícitas: reglas que restringen los valores que pueden tomar las variables en un conjunto dado. • Implícitas: Indican la relación existente entre los posibles valores de los componentes xi’s para que éstos puedan formar parte de una n-tupla solución. • Ejemplo de las n-reinas VA: fundamentos Los nodos fracasos son detectados mediante un test de factibilidad, el cual es un mecanismo que permite detectar si las restricciones (explícitas o implícitas) del problema son violadas. Este mecanismo de evaluación será más costoso cuanto más compleja sea las restricciones. La eficiencia el algoritmo está muy asociada a este mecanismo de evaluación En resumen: La búsqueda de solución en el árbol de expansión se hace con un recorrido en profundidad. • La construcción se realiza por etapas • Tipos de Nodos: 1. Nodos vivos 2. Nodo en expansión 3. Nodos muertos La técnica de VA suele estar asociada a la recursión VA: Esquema general (una solución) En cada llamada al procedimiento se toma una variable y se le asignan todos los valores posibles (mediantes next), llamando a su vez al procedimiento para cada uno de los nuevos estados. void VueltaAtras(int etapa) { opciones.iniciar(); while(!opciones.fin()) &&(! exito)){ Opcion x = opciones.next(); solucion.anotar(x); if (!solucion.esCompleta()){ VueltaAtras(etapa+1); if( ! exito) solucion.cancelar(x); } else exito= true } } • Ordenes de Ejecución Exponenciales: – Suponiendo que la solución sea de la forma (x1, x2, …., xn). – En el peor caso se generarán todas las posibles combinaciones para cada xi. – Si el número de posibles valores para cada xi es mi (i.e. mi = 2), entonces se generan: Tiempo Exponencial • Ordenes de Ejecución Factoriales: – Suponiendo que la solución sea de la forma (x1, x2, …., xn). – En el peor caso se generarán todas las permutaciones posibles para cada xi. Tiempo Factorial VA se usa en muchas aplicaciones hoy día. Por ejemplo, se aplica en – la implementación de lenguajes de programación tales como el Prolog – en los análisis sintácticos de los compiladores. – En algoritmos de inteligencia artificial, como es el caso del A*. VA: Aplicaciones 8 reinas…por fuerza bruta Una búsqueda por fuerza bruta examinaría todas las combinaciones (ciegas) de las 8 piezas en un tablero con 64 celdas, lo cual equivale inicialmente a (las reinas podrían estar en la misma celda !!).: 648 = 281.474.976.710.656 posibles configuraciones !!  Método impracticable !! Una mejora consiste en eliminar aquellas configuraciones que colocan a dos reinas en el mismo cuadrado. En este sentido, dependiendo de la representación tendremos un número diferente de combinaciones posibles. Por ejemplo, 1. Si se representase como un vector de 64 posiciones donde cada posición puede tomar un valor entre 1 y 8 indicando claramente cuál de las reinas está en esa posición entonces tendríamos: 64! / 56! = 178.462.987.637.760 posibles configuraciones  Sigue siendo un Método impracticable !! 2. Si la solución se representase como un vector de valores lógicos de 64 casillas, donde un “cierto” indica que en esa casilla hay una reina (pero no distingue cuál de ellas) tendríamos 64! / (8! 56!) = 4.426.165.368  Sigue siendo un Método impracticable !! Además, para cada una de estás configuraciones habría que realizar un test de factibilidad en la cual se detecte si ninguna reina es atacada por alguna de las otras. 8 reinas…por fuerza bruta Una mejora consiste en no colocar más de una reina por fila. En este caso la representación se reduce a un vector de 8 enteros lo cual nos da SÓLO: 88 = 224 = 16,777,216 posibles configuraciones ciegas Sigue siendo un Método impracticable !! Algoritmo de Fuerza Bruta: La primera solución es obtenida después de considerar 1.299.852 situaciones !! 8 reinas…por fuerza bruta Otra mejora consiste en no colocar además más de una reina por columna. En este caso la representación se reduce a un vector de 8 enteros DIFERENTES lo cual EQUIVALE A UNA PERMUTACIÓN DE 8 ENTEROS, lo que nos da SÓLO: 8! = 40.320 posibles configuraciones ciegas Algoritmo de Fuerza Bruta 2: La primera solución es obtenida después de considerar 2.830 situaciones !! Problema generalizado: en todas las propuestas de FB nunca se comprueba si una situación es solución hasta no haber colocado todas las reinas en el tablero lo cual da lugar a intentos inútiles !! public class Reinas { int n; // tamaño del tablero int [ ] solucion; boolean exito; public Reinas (int tam) { n = tam; solucion = new int [n]; } void VA(int k) { // k es la etapa int i; if (k<n) { for(i = 0; (i<n)&&(!exito); i++) { solucion[k] = i; if (valido(k)) { if (k<n-1) VA(k+1); else exito = true; } } } } ... Problema de las N reinas … Implementación para VA boolean valido(int k) { int i; for (i=0;i<k;i++) if ((solucion[i]==solucion[k]) || (valAbs(solucion[i]-solucion[k])==valAbs(i-k))) return false; return true; } int valAbs(int x) { return (x<0)?(-x):x; } public int [ ] vueltaAtras() { exito = false; VA(0); return solucion; } Problema de las N reinas … Implementación para VA void VA_todas(int k, Vector v) { // k es la etapa int i; if (k<n) { solucion[k] = 0; for(i = 0; i<n; i++) { solucion[k] = i; if (valido(k)) { if (k<n-1) VA_todas(k+1,v); else { v.addElement(solucion); //comunicar solucion for (int j=0;j<solucion.length;j++) System.out.print(solucion[j]+", "); System.out.println(); } } } } } Problema de las N reinas … Implementación para VA Sudoku: Implementación proc sudoku_VA (↓i, ↓j: Nat; ↓sol[1..9, 1..9] de 0..9; ↓fija[1..9, 1..9] de Bool) si NOT (fija [i, j) entonces para k ← 1 hasta 9 hacer sol[i, j] ← k //marcar si es_factible (i, j, sol) entonces EN CASO DE QUE i = 9 ^ j = 9 → mostrarPorPantalla(sol); i < 9 ^ j = 9 → sudoku_VA (i+1, 1, sol, fija); i <= 9 ^ j < 9 → sudoku_VA( i , j+1, sol, fija); FinCASOS; finsi; sol[i, j] ← 0; //Desmarcar finpara; EnOtroCaso // si fija[i, j] = Cierto EN CASO DE QUE i = 9 ^ j = 9 → mostrarPorPantalla(sol); i < 9 ^ j = 9 → sudoku_VA (i+1, 1, sol, fija); i <= 9 ^ j < 9 → sudoku_VA( i , j+1, sol, fija); FinCASOS; finsi; finproc; El Sudoku se representa por una matriz sol [1..9,1..9] de 0..9 donde sol[i, j] representa el valor que toma dicha celda, correspondiéndose el valor 0 con una casilla vacía. Se usa la matriz fija[1..9, 1..9] de valores lógicos donde fija[i, j] es verdadero si inicialmente la celda sol[i,j] contiene un valor que no se puede modificar. La función “es_factible” comprueba para una celda determinada, que no se repita su valor en la misma fila, columna o subgrupo de 3x3, atendiendo así a la restricción que comentábamos en la descripción detallada del problema. La llamada inicial es: Sudoku_VA(1,1,sol,fija) Sudoku: Implementación función es_factible (↓i, ↓j : Nat; ↓sol[1..9, 1..9] de 0..9):Lógico var valido: Lógico; k, l : Natural; inicio valido ← cierto k ← 1 mientras (k <= 9 ^ valido) hacer //Comprobamos la fila si ( sol[i, j] = sol[i, k] ^ k ≠ j ) entonces valido ← falso finsi k ← k + 1 finmientras k ← 1 mientras (k <= 9 ^ valido) hacer //Comprobamos la columna si ( sol[i, j] = sol[k, j] ^ k ≠ i ) entonces valido ← falso finsi k ← k + 1 finmientras k ← correspondencia3x3(i) //Comprobamos el subgrupo de 3x3 mientras ( k < correspondencia3x3(i) + 3 ^ valido ) hacer l ← correspondencia3x3(j) //Comprobamos el subgrupo de 3x3 mientras ( l < correspondencia3x3(j) + 3 ^ valido) hacer si (sol[i, j]=sol[k, l] ^ i≠k ^ j≠l) entonces valido←falso finsi l ← l + 1 finmientras k ← k + 1 finmientras devolver valido Finfunción función correspondencia3x3 (↓i: Nat): Natural var k,resultado: Natural inicio si ( i % 3 = 0) entonces k← i DIV 3 EnOtroCaso k ← i DIV 3 + 1 finsi SEA k IGUAL A 1: resultado ← 1 2: resultado ← 4 3: resultado ← 7 FINSEA devolver resultado finfunción Esta función se utiliza para averiguar la celda inicial desde la que haremos la comprobación de factibilidad de una celda determinada en su correspondiente subgrupo de 3x3 celdas. Problema del recorrido del caballo 23 10 15 4 25 16 5 24 9 14 11 22 1 18 3 6 17 20 13 8 21 12 7 2 19 Dado un tablero de ajedrez de n x n posiciones, y un caballo colocado en cualquier posición, determinar los n2-1 movimientos del caballo de tal manera que todas las casillas sean visitadas una sola vez, si tal secuencia de movimientos existe. Una Solución para tablero 8 x 8 (son 63 saltos del caballo) Una Solución para tablero 5 x 5 (son 24 saltos del caballo empezando desde la casilla 1) Problema del recorrido del caballo: implementación //@pre: (1<=k) && (k<=n*n) // k es la etapa, (x,y) las coordenadas donde está el caballo. boolean VA(int k, int x, int y) { int orden = 0; //Recorre las 8 posibilidades desde (x,y) boolean exito = false; int u,v; // Nuevas coordenadas while ( (!exito) && (orden<movX.length) ) { //calculamos a donde salta u = x + movX[orden]; v = y + movY[orden]; // posible salto if ((0<=u)&&(u<n)&&(0<=v)&&(v<n)&& //dentro? (tablero[u][v]==0)) { // previamente visitado? tablero[u][v] = k; //anotar opción if (k<n*n) { //hemos acabado? exito = VA(k+1,u,v); if (!exito) tablero[u][v] = 0; //cancela } else exito = true; } // if orden++; } // while return exito; } Cuando no hay posibilidad de continuar con el movimiento hay que dar marcha atrás y continuar con otra alternativa 10 // (x,y) son las coordenadas desde donde // empieza a moverse el caballo. //@pre: (0<=x)&&(x<n)&&(0<=y)&&(y<n) // devuelve el tablero solución. public int [ ][ ] vueltaAtras(int x, int y) { tablero[x][y] = 1; VA(2,x,y); return tablero; } } // fin de class Caballo Problema del recorrido del caballo: implementación Inicialmente se parte de una casilla (x,y) cualquiera que esté dentro del tablero. INNER Dado un conjunto S = [s],-*- ,s8n) de números naturales, y un número d encontrar un subconjunto 5” C S tal que > ses s< d e Si RCS, entonces — o bien Y ,¿gT > d, 20d rerTS ses! 8
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved