1 / 15

3. Recursividad

3. Recursividad. ¿Qué es y para qué se usa?. Al programar en forma recursiva, buscamos dentro de un problema otro sub-problema que posea su misma estructura Ejemplo : Calcular x n . . // Version 1, estrategia: x n = x * x n-1 public static float elevar ( float x, int n )  {

ivrit
Download Presentation

3. Recursividad

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 3.Recursividad

  2. ¿Qué es y para qué se usa? • Al programar en forma recursiva, buscamos dentro de un problema otro sub-problema que posea su misma estructura • Ejemplo: Calcular xn. // Version 1, estrategia: xn = x * xn-1 public static float elevar( float x, int n )  {     if( n==0 )         return 1;     else         return x * elevar(x, n-1); } • // Version 2, estrategia xn = xn/2 * xn/2 • public static float elevar( float x, int n )  { •     if( n==0 ) •         return 1;  •    else if( n esimpar )   •       return x * elevar( x, n-1 ); •     else • return elevar( x*x, n/2 );  }

  3. Ejemplo 2: Las torres de Hanoi • Pasar las argollas desde la estaca 1 a la 3 • Restricciones: • Mover una argolla a la vez • Nunca puede quedar una argolla mas grande sobre una más pequeña • public class TorresDeHanoi { • static void Hanoi( int n, int a, int b, int c ) { • if( n>0 ) { • Hanoi( n-1, a, c, b ); • System.out.println( a + " --> " + c ); • Hanoi( n-1, b, a, c ); • } • } •   public static void main( String[] args ) { • Hanoi( Integer.parseInt(args[0]), 1, 2, 3 ); • } • }

  4. Breve análisis • Cada invocación del método Hanoi genera a su vez dos llamadas recusrivas • Cada llamada recursiva se hace “achicando” el problema en una argolla • Cada ejecución toma tiempo constante • T(n) = 1 + 2T(n-1) • En cada nivel se tienen 21 ejecuciones • Σ 2i = 2n+1 - 1 i = 0..n • Se puede demostrar por inducción 20 T(n) 21 T(n-1) T(n-1) 22 T(n-2) T(n-2) T(n-2) T(n-2) N veces 2n T(1) T(1) T(1) T(1) T(1) . . .

  5. Ejemplo 3: Generar permutaciones • Se tiene un arreglo a[0] . . a[n-1] • Se quieren generar (e imprimir) todas las permutaciones posibles • Estrategia: intercambiar el primer elemento con el i-esimo y generar todas las permutaciones para los n-1 siguientes, i = 0..n-1 • Ej 1,2,3 • 1 2,3 • 1 3,2 • 2 1,3 • 2 3,1 • 3 2,1 • 3 1,2

  6. El programa public class PermutaArreglo {  static void permutaciones( int[] x, intini, int fin) { if( ini == fin ) { imprimir(x); return;} for (inti = ini; i<= fin; i++) { intercambiar(x,ini,i); permutaciones(x, ini+1, fin); intercambiar(x,ini,i); } }  public static void imprimir(int[] x) { for(inti = 0; i < x.length; i++) System.out.print(x[i]+" "); System.out.println(); }   public static void main( String[] args ) { int[] a = {1,2,3,4,5}; permutaciones( a,0,4 ); }  public static void intercambiar(int[] x, int y, int z) { intaux = x[y]; x[y] = x[z]; x[z] = aux; }  }

  7. Breve análisis • Cada invocación del método permutaciones genera a su vez n-1 llamadas recusrivas • Cada llamada recursiva se hace “achicando” el problema en un elemento • Cada ejecución toma orden n (por el for) • T(n) = n + nT(n-1) • En cada nivel se tienen n(n-1)(n-2)…(n-i+1) ejecuciones, cada una efectúa k(n-i) instrucciones • En el último nivel tenemos la n ejecuciones cada una con un elemento • n • n(n-1) • n(n-1)(n-2) • n! • Cota superior si en todos los niveles colocamos n! y tenemos n niveles tendriamosaprox (n+1)! • El resultado está entre n! y (n+1)! (IGUAL MUCHO)

  8. El backtraking • Solucionar un problema por prueba y error • Se basa en generar todas las posibles soluciones a un problema y probarlas • Por esto mismo, el tiempo requerido para solucionar el problema puede explotar • Ejemplos típicos: las n-reinas, el caballo, el laberinto

  9. Ejemplo 1: el laberinto • Se tiene una matriz de caracteres de dimensiones MxN que representa un laberinto. • Carácter ‘*’ significa pared, no se puede pasar • Carácter ‘ ‘ implica se puede pasar. • Carácter ‘&’ indica salida del laberinto • publicstaticboolean salida(char[][] x, int i, int j) retorna true si a desde la posición i,j se puede encontrar una salida. * * * * * * * * * *   *       *   * *   * * * & *       *   *   * * * *   *   *   * *   *           * *   *       *   * * * * * * * * * *

  10. Algoritmo backtraking • Recursivamente esto se puede programar de la siguiente manera probando todos los caminos posibles: • si en la posición donde estoy (i,j) hay un ‘*’ no hay salida y retorno false. • si en la posición donde estoy (i,j) hay un ‘&‘ entonces estoy fuera y retorno true. • si estoy en posición (i,j) y hay un espacio, pruebo recursivamente si hay salida por alguna de las 4 vecinas (i+1,j), (i-1,j), (i,j+1), (i,j-1). • si alguna de las llamadas retorna true, yo retorno true (suponemos que no se puede mover en diagonal). Si todas retornanfalse, retorno false.

  11. Prgrama: version 1 publicstatic salida1(char[][] x,i,j) { if (x[i][j] == ‘&’) returntrue; if (salida1(x, i+1, j)) returntrue; if (salida1(x, i-1, j )) returntrue; if (salida1(x, i, j+1)) returntrue; if (salida1(x, i, j-1,)) returntrue; returnfalse; } • Esta solución tiene el problema que puede generar llamadas infinitas. Por ejemplo, si llamamos a salida(x, a, b, M,N) y esá vacía pero no es salida, esta llamará a salida(x,a+1,b,M,N). Si la celda (a+1,b) está vacía y no es salida, llamará a salida(x, a+1-1,b,M,N), generandose así un ciclo infinito.

  12. Programa version 2 • Para evitar esto podemos ir “marcando” (por ejemplo, con una x) los lugares por donde hemos pasado para no pasar de nuevo por ahí: publicstaticboolean salida1( char[][] x, i, j) { if (x[i][j] == ‘&’) returntrue; if (x[i][j] == '*' || x[i][j] == '+') returnfalse; x[i][j] = ‘o'; if (salida1(x, i+1, j)) returntrue; if (salida1(x, i-1, j)) returntrue; if (salida1(x, i, j+1)) returntrue; if (salida1(x, i, j-1)) returntrue; returnfalse; • }

  13. Rescatando el camino • Podemos retornar un string que contenga la secuencia de (i,j) por donde hay que pasar para llegar a la salida. Para eso debemos modificar el encabezado publicstatic String sailda(char[][] x, int i, int j) { if (x[i][j] == ‘&’) return "("+i+","+j+")"; String l = s.nextLine(); if (x[i][j] == '*' || x[i][j] == ‘o') returnnull; x[i][j] = '+'; String camino = (salida2(x, i+1, j)); if (camino != null) return "("+i+","+j+")"+camino; camino = (salida2(x, i-1, j)); if (camino != null) return "("+i+","+j+")"+camino; camino = (salida2(x, i, j+1)); if (camino != null) return "("+i+","+j+")"+camino; camino = (salida2(x, i, j-1)); if (camino != null) return "("+i+","+j+")"+camino; returnnull; }

  14. Camino mas corto • Queremos saber cuánto mide el camino (de existir) entre la celda i,j y la salida más próxima. Para esto tenemos que probar todas las posibilidades y nos quedamos con la mejor (más corta): publicstaticintsailda(char[][] x, int i, intj) { if (x[i][j] == ‘&’) return 0; String l = s.nextLine(); if (x[i][j] == '*' || x[i][j] == ‘o') return -1; intmascorto = -1; x[i][j] = '+'; intcamino = (salida3(x, i+1, j)); if (camino != -1 && camino < mascorto) mascorto = camino; camino = (salida3(x, i-1, j)); if (camino != -1 && camino < mascorto) mascorto = camino; camino = (salida3(x, i, j+1)); if (camino != -1 && camino < mascorto) mascorto = camino; camino = (salida3(x, i, j-1)); if (camino != -1 && camino < mascorto) mascorto = camino; x[i][j] = ' '; if (mascorto == -1) return -1; returnmascorto +1; }

  15. Ejemplo: mejor jugada del gato • función que evalúa qué tan buena es una jugada en el gato. • suponiendo que tanto mi contrincante como yo vamos a seguir escogiendo la mejor jugada posible en cada etapa. • retorno 1 si gano con la jugada x,y, 0 si empato, -1 si pierdo intgato(char[][] t, int x, int y, char z) { t[x][y] = z; if (gano(t, z)) return 1;    if (empate(t,x,y,z)) return 0; char contrincante = 'O'; if (z == 'O')contrincante = 'X'; intmejorCont = -1;    for (inti = 0; i <= 2; i++)     for (int j = 0; j <= 2; j++)        if (t[i][j] == ' ') { int c = gato(t,i,j,contrincante);          if (c > mejorCont) mejorCont = c;        }     return -mejorCont: }

More Related