Vous êtes sur la page 1sur 22

Backtracking

El Arte de la Programacin Rpida

Backtracking
Los algoritmos de vuelta atrs se utilizan para encontrar soluciones a un problema. No siguen unas reglas para la bsqueda de la solucin simplemente una bsqueda sistemtica, que ms o menos viene a significar que hay que probar todo lo posible hasta encontrar la solucin o encontrar que no existe solucin al problema. Para conseguir este propsito, se separa la bsqueda en varias bsquedas parciales o subtareas. Asimismo, estas subtareas suelen incluir ms subtareas. El tratamiento general de estos algoritmos es de naturaleza recursiva. Por qu se llaman algoritmos de vuelta atrs?. Porque en el caso de no encontrar una solucin en una subtarea se retrocede a la subtarea original y se prueba otra cosa distinta (una nueva subtarea distinta a las probadas anteriormente).

Backtracking
Backtracking = Fuerza bruta Mtodo sistemtico que itera a travs de todas las combinaciones posibles del espacio de bsqueda. Es una tcnica general que debe ser adaptada para cada aplicacin particular. Siempre puede encontrar todas las soluciones existentes El problema es el tiempo que toma en hacerlo

Backtracking

Backtracking: Modelacion
En general representamos la solucin como un vector a = (a1,a2,...,an), donde: Cada ai es seleccionado de un conjunto Si. Puede representar, por ejemplo: Una situacin donde ai es el i-simo elemento de una permutacin. Un subconjunto (ai es verdadero sii el i-simo elemento del universo pertenece al conjunto. Secuencia de movimientos en un juego o camino en un grafo, donde ai contiene el i-simo evento en la secuencia.

Backtracking: Algoritmo
backtrack(int a[], int k, data input) {int c[MAX_CANDIDATES]; int ncandidates; int i; if(is_a_solution(a,k,input)){ process_solution(a,k,input); else { k = k+1; ncandidates=construct_candidates(a,k,input,c); for (i=0;i<ncandidates;i++){ a[k] = c[i]; backtrack(a,k,input); if (finished) return; } } }

Backtracking: construccin de subconjuntos

Podemos construir los 2n subconjuntos de n elementos iterando sobre los 2n posibles vectores de longitud n Cada posicin tiene un true o false. Es decir, usando la notacin general, Sk=(true,false).

Backtracking: construccin de subconjuntos


Generate_subsets(int n){ int a[NMAX]; backtrack(a,0,n); } Salida: {123} {12} {13} {1} {23} {2} {3} {}

Backtracking: construccin de subconjuntos


Generate_subsets(int n){ int a[NMAX]; backtrack(a,0,n); } Salida: {123} {12} {13} {1} {23} {2} {3} {}

Backtracking:
Ej Arbol de Busqueda No necesariamente Binario

Backtracking: Modelacion
A menudo ocurre que el rbol o grafo que se genera es tan grande que encontrar una solucin o encontrar la mejor solucin entre varias posibles es computacionalmente muy costoso. En estos casos suelen aplicarse una serie de restricciones, de tal forma que se puedan podar algunas de las ramas, es decir, no recorrer ciertas subtareas. Esto es posible si llegado a un punto se puede demostrar que la solucin que se obtendr a partir de ese punto no ser mejor que la mejor solucin obtenida hasta el momento. Si se hace correctamente, la poda no impide encontrar la mejor solucin.

Backtracking: Modelacion
A veces, es imposible demostrar que al hacer una poda no se est ocultando una buena solucin. Sin embargo, el problema quizs no pida la mejor solucin, sino una que sea razonablemente buena y cuyo coste computacional sea bastante reducido. Esa es una buena razn para aumentar las restricciones a la hora de recorrer un nodo. Tal vez se pierda la mejor solucin, pero se encontrar una aceptable en un tiempo reducido.

Backtracking: Modelacion

Los algoritmos de vuelta atrs tienen un esquema genrico, segn se busque una o todas las soluciones. Puede adaptarse fcilmente segn las necesidades de cada problema. A continuacin se exponen estos esquemas, extrados de Wirth (ver Bibliografa). Los bloques se agrupan con begin y end, equivalentes a los corchetes de C, adems estn tabulados.

Backtracking: Modelacion Esquema para una solucin:


procedimiento ensayar (paso : TipoPaso) repetir | seleccionar_candidato | if aceptable then | begin | anotar_candidato | if solucion_incompleta then | begin | ensayar(paso_siguiente) | if no acertado then borrar_candidato | end | else begin | anotar_solucion | acertado <- cierto; | end hasta que (acertado = cierto) o (candidatos_agotados) fin procedimiento

Backtracking: Modelacion
Esquema para todas las soluciones:

procedimiento ensayar (paso : TipoPaso) para cada candidato hacer | seleccionar candidato | if aceptable then | begin | anotar_candidato | if solucion_incompleta then | ensayar(paso_siguiente) | else | almacenar_solucion | borrar_candidato | end hasta que candidatos_agotados fin procedimiento

Backtracking: Modelacion Ej La Vuelta del Caballo:


Se dispone de un tablero rectangular, por ejemplo el tablero de ajedrez, y de un caballo, que se mueve segn las reglas de este juego. El objetivo es encontrar una manera de recorrer todo el tablero partiendo de una casilla determinada, de tal forma que el caballo pase una sola vez por cada casilla. Una variante es obligar al caballo a volver a la posicin de partida en el ltimo movimiento. Por ltimo se estudiar como encontrar todas las soluciones posibles partiendo de una misma casilla.

Backtracking: Modelacion Ej La Vuelta del Caballo:


Para resolver el problema hay que realizar todos los movimientos posibles hasta que ya no se pueda avanzar, en cuyo caso hay que dar marcha atrs. O hasta que se cubra el tablero. Adems, es necesario determinar la organizacin de los datos para implementar el algoritmo. Cmo se mueve un caballo?. Para aquellos que no sepan jugar al ajedrez se muestra un grfico con los ocho movimientos que puede realizar. Estos movimientos sern los ocho candidatos.

Backtracking: Modelacion Ej La Vuelta del Caballo:


Con las coordenadas en las que se encuentre el caballo y las ocho coordenadas relativas se determina el siguiente movimiento. Las coordenas relativas se guardan en dos arrays: ejex = [2, 1, -1, -2, -2, -1, 1, 2] ejey = [1, 2, 2, 1, -1, -2, -2, -1] El tablero, del tamao que sea, se representar mediante un array bidimensional de nmeros enteros. A continuacin se muestra un grfico con un tablero de tamao 5x5 con todo el recorrido partiendo de la esquina superior izquierda.

Backtracking: Modelacion Ej La Vuelta del Caballo:


Cuando se encuentra una solucin, una variable que se pasa por referencia es puesta a 1 (cierto). Puede hacerse una variable de alcance global y simplificar un poco el cdigo, pero esto no siempre es recomendable. Para codificar el programa, es necesario considerar algunos aspectos ms:
entre otras cosas no salirse de los lmites del tablero y no pisar una casilla ya cubierta (seleccin del candidato). Se determina que hay solucin cuando ya no hay ms casillas que recorrer.

#include <stdio.h>
#define N 5 #define ncuad N*N void mover(int tablero[][N], int i, int pos_x, int pos_y, int *q); const int ejex[8] = { -1,-2,-2,-1, 1, 2, 2, 1 }, ejey[8] = { -2,-1, 1, 2, 2, 1,-1,-2 }; int main(void) { int tablero[N][N]; /* tablero del caballo. */ int i,j,q; /* inicializa el tablero a cero */ for (i = 0; i < N; i++) for (j = 0; j < N; j++) tablero[i][j] = 0; /* pone el primer movimiento */ tablero[0][0] = 1; mover(tablero,2,0,0,&q); if (q) { /* hay solucion: la muestra. */ for (i = 0; i < N; i++) { for (j = 0; j < N; j++) printf("%3d ", tablero[i][j]); putchar('\n'); } } else printf("\nNo existe solucion\n"); return 0; }

void mover(int tablero[][N],int i, int pos_x, int pos_y, int *q) { int k, u, v; k = 0; *q = 0; do { u = pos_x + ejex[k]; v = pos_y + ejey[k]; /* seleccionar candidato */ if (u >= 0 && u < N && v >= 0 && v < N) { /* esta dentro de los limites? */ if (tablero[u][v] == 0) { /* es valido? */ tablero[u][v] = i; /* anota el candidato */ if (i < ncuad) { /* llega al final del recorrido? */ mover(tablero,i+1,u,v,q); if (!*q) tablero[u][v] = 0; /* borra el candidato */ } else *q = 1; /* hay solucion */ } } k++; } while (!*q && k < 8);

Cambiando el valor de N puede obtenerse una solucin para un tablero cuadrado de tamao N. A continuacin, se muestra una adaptacin del procedimiento que muestra todas las soluciones. Si se ejecuta para N = 5 se encuentra que hay 304 soluciones partiendo de la esquina superior izquierda. Cuando se encuentra una solucin se llama a un procedimiento (no se ha codificado aqu) que imprime todo el tablero. void mover(int tablero[][N],int i, int pos_x, int pos_y) { int k, u, v; for (k = 0; k < 8; k++) { u = pos_x + ejex[k]; v = pos_y + ejey[k]; if (u >= 0 && u < N && v >= 0 && v < N) { /* esta dentro de los limites */ if (tablero[u][v] == 0) { tablero[u][v] = i; if (i < ncuad) mover(tablero,i+1,u,v); else imprimir_solucion(tablero); tablero[u][v] = 0; } } } }

Vous aimerez peut-être aussi