memoria final proyecto algoritmos avanzados

8

Click here to load reader

Upload: juan-sopale

Post on 07-Aug-2015

22 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Memoria Final Proyecto Algoritmos Avanzados

Proyecto de Algoritmos Avanzados:

El laberinto con ramificación y poda

Alumnos:Juan Antonio Sopale Thompson

Jorge Colmenar CasasVíctor Puerta Rodriguez

Page 2: Memoria Final Proyecto Algoritmos Avanzados

Índice de contenidoObjetivos del trabajo.............................................................................................................................3Descripción del trabajo realizado.........................................................................................................3Algoritmo codificado y decisiones de diseño.......................................................................................3Análisis de la complejidad....................................................................................................................6Conclusiones.........................................................................................................................................7Bibliografía...........................................................................................................................................8

2 de 8

Page 3: Memoria Final Proyecto Algoritmos Avanzados

OBJETIVOS DEL TRABAJO

La intención de este trabajo será ahondar en la codificación del algoritmo para recorrer un laberinto hasta llegar a la meta correspondiente. La peculiaridad de nuestro trabajo es que además de buscar una solución tratamos de encontrar la solución cuyo camino sea el mínimo posible hasta la meta. Para ello usaremos la técnica de ramificación y poda con cotas para buscar la solución óptima a nuestro problema.

DESCRIPCIÓN DEL TRABAJO REALIZADO

Descrito ya el objetivo del trabajo procederemos con la descripción del trabajo realizado..

Primeramente, hemos analizado el problema del laberinto, y como encontrar una solución válida al problema. Una vez analizado, procedemos a buscar cual es la estructura de datos que vamos a usar para representar el laberinto. Ya con la estructura elegida, evaluamos las restricciones del problema (movimientos en el laberinto, muros, límites del laberinto y casillas ya transitadas) y las adaptamos a nuestra estructura. Entonces tenemos ya todas las características del laberinto representadas y procedemos a evaluar y aplicar la ramificación y poda al laberinto.

ALGORITMO CODIFICADO Y DECISIONES DE DISEÑO

Decisión de diseño:

Tabla:

3 de 8

Page 4: Memoria Final Proyecto Algoritmos Avanzados

La tabla tiene dimensiones NxM, por tanto el número de casillas es N*M. En nuestro caso usaremos un laberinto cuyo número de filas y número de columnas tienen valores independientes, es decir, N y M no tienen porque ser iguales.El contenido de la tabla, las casillas, pueden ser de tres tipos:

• Con valor igual a 0: Se corresponde con una casilla del laberinto vacía.• Con valor igual a -1: Se corresponde con un un muro del laberinto.• Con valor igual a un número natural (que no sea 0): Se corresponde con una casilla del

laberinto que ya ha sido transitada y que antes de ser transitada tenía valor igual a 0. El valor de la casilla es igual al número de pasos que llevemos dados en el laberinto.

Una vez tenemos el laberinto representado en una matriz, la serie de movimientos que podemos efectuar son: Ir hacia la derecha, hacia abajo, hacia la izquierda y hacia arriba. Cada uno de estos movimientos son válidos siempre y cuando la casilla a la que nos desplazamos tenga valor 0.Para los desplazamientos usaremos dos vectores:

• Vector que incrementa la coordenada x• Vector que incrementa la coordenada y

Ambos vectores tienen un tamaño de 4 elementos debido a que sólo tenemos 4 movimientos posibles. Nuestra posición actual está definida por un x y un y determinados. Cuando nos movamos, a esa posición actual le sumamos Vx(i) y Vy(i), donde Vx y Vy son los vectores de incremento de la coordenada x y la coordenada y respectivamente, e i es el movimiento que se realiza (i: con valor 0 derecha, con valor 1 abajo, con valor 2 izquierda y con valor 3 arriba).

Respecto a las cotas hacemos uso de la cota superior. Inicialmente la cota superior es el total de casillas que componen el laberinto. Conforme vamos obteniendo soluciones actualizamos el valor de la cota a una mejor solución. De ese modo al tener una cota mejor estimada nos permite ahorrarnos soluciones peores.

Algoritmo codificado:

public class Laberinto {

private boolean encontrado = false; //si encuentra una solución 'encontrado'=true private int cota; //nos indica el número de pasos mínimos posibles hasta el momento private final int MURO = -1; //el muro está indicado en el laberinto como -1 private int laberinto[][]; //matriz que representa el laberinto private int solucion [][]; //matriz con la solución del laberinto private int dim1; //número de columnas private int dim2; //número de filas

public Laberinto(int dim1, int dim2) { //este constructor inicializa el laberinto this.dim1 = dim1; this.dim2 = dim2; cota = dim1*dim2; //inicializamos la cota a un valor igual al número de casillas del laberinto. laberinto = new int[dim1][dim2]; //asignamos dimensiones al laberinto. for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { laberinto[i][j] = 0; } }

}

4 de 8

Page 5: Memoria Final Proyecto Algoritmos Avanzados

public void ponerMuro(int x, int y) { //esta función nos permite poner los muros que queramos. laberinto[x][y] = MURO; } public boolean resolver () { int nodo[] = new int[2];//nodo actual con 2 elementos la x y la y. //Las dos siguientes variables permiten los movimientos hacia derecha con incrX(0) e incrY(0), //hacia abajo con incrX(1) e incrY(1), hacia la izquierda con incrX(2) e incrY(2) y hacia arriba //con incrX(3) e incrY(3) int[] incrX = {1, 0, -1, 0}; int[] incrY = {0, 1, 0, -1};

//Nos siuamos en la posición incial 0,0 del laberinto: laberinto[0][0] = 1; nodo[0] = 0; nodo[1] = 0; solucion = new int[dim1][dim2]; //Matriz en la que tendremos la solución del laberinto expandir(solucion, laberinto, nodo, dim1, dim2, incrX, incrY, 1); if (encontrado) { //Si hay solución válida imprimimos la solución for (int i = 0; i < dim2; i++) { for (int j = 0; j < dim1; j++) { System.out.print(solucion[j][i] + "\t"); } System.out.println(); } return true; } else { // Si no imprimimos que no hemos encontrado solución System.out.println("No se ha encontrado solucion"); return false; } } private void expandir(int[][] solucion, int laberinto[][], int[] nodo, int dim1, int dim2, int[] incrX, int[] incrY, int pasos) { int[] nodoAux = new int[2]; for (int i = 0; i < incrX.length; i++) { //Nos desplazamos en una dirección (derecha o izquierda o arriba o abajo) nodoAux[0] = nodo[0] + incrX[i]; nodoAux[1] = nodo[1] + incrY[i];

if (((nodoAux[0] >= 0) && (nodoAux[0] < dim1)) && ((nodoAux[1] >= 0) && (nodoAux[1] < dim2))) {//si estan dentro del rango del laberinto. if ((laberinto[nodoAux[0]][nodoAux[1]] == 0) && (pasos < cota)) { //si no estamos en un muro o casilla ocupada y no superamos la cota: laberinto[nodoAux[0]][nodoAux[1]] = pasos + 1;

pasos++;

if ((nodoAux[0] == dim1 - 1) && (nodoAux[1] == dim2 - 1)) {//si estamos en la meta: encontrado = true; cota = pasos - 1; //actualizamos la cota. //copiamos solución válida en el vector solución: for (int m = 0; m < dim1; m++) { System.arraycopy(laberinto[m], 0, solucion[m], 0, dim2); }

laberinto[nodoAux[0]][nodoAux[1]] = 0;//deshacemos

} else { //si no es solución seguimos expandiendo expandir(solucion, laberinto, nodoAux, dim1, dim2, incrX, incrY, pasos); //deshacemos: laberinto[nodoAux[0]][nodoAux[1]] = 0; pasos--; } } } } }

5 de 8

Page 6: Memoria Final Proyecto Algoritmos Avanzados

//Caso de prueba:

public static void main(String[] args) {// TODO Auto-generated method stubLaberinto lab = new Laberinto(6,6);

lab.ponerMuro(0, 4); lab.ponerMuro(1, 2); lab.ponerMuro(2, 1); lab.ponerMuro(2, 2); lab.ponerMuro(2, 4); lab.ponerMuro(3, 2); lab.ponerMuro(3, 4); lab.ponerMuro(4, 0); lab.ponerMuro(4, 2); lab.ponerMuro(5, 4); lab.resolver();

}

}

ANÁLISIS DE LA COMPLEJIDAD

Respecto al análisis de la complejidad, depende más bien de la cantidad de muros que haya, es decir, es variable. Por tanto sacar un valor estimado de complejidad no es significativo. Se puede ver claramente la influencia de los muros en la complejidad:

6 de 8

Ejemplo 1

Ejemplo 2

Page 7: Memoria Final Proyecto Algoritmos Avanzados

En el ejemplo 1, estamos en la posición inicial rodeados de muros. La complejidad sería O(1) ya que no podemos hacer ningún movimiento válido y tampoco podemos llegar a ninguna solución.. En cambio en el ejemplo 2 para llegar a la meta recorremos N columnas más M filas hasta llegar a la meta, complejidad O(N + M). Como vemos, según estén distribuidos los muros tenemos una complejidad u otra, por consiguiente variable.

Otro enfoque de la complejidad está en el uso de la ramificación y poda con cota. Con este uso conseguimos podar ramas inservibles y por tanto la complejidad en comparación de no usar cotas es menor. Un árbol de recursión grande con el uso de cotas puede quedar reducido a algo significativamente más pequeño. Por eso se aprecia una mejora en la complejidad.

CONCLUSIONES

Como hemos comprobado, la ramificación y poda puede ser aplicado a una variedad de problemas consiguiendo una mejora considerable a la hora de buscar soluciones óptimas. Aplicado al problema del laberinto nos ahorramos tener que recorrer caminos que no nos llevan a soluciones mejores, es decir, ganamos en tiempo de computación. Para buscar el camino mínimo en el laberinto y en general para cualquier problema de optimización, el uso de la ramificación y poda es una técnica eficiente.

7 de 8

Page 8: Memoria Final Proyecto Algoritmos Avanzados

BIBLIOGRAFÍA

• http://www.lcc.uma.es/~av/Libro/CAP7.pdf

8 de 8