Back Tracking

  • 15,074 views
Uploaded on

Descripción explicativa del esquema algorítmico de vuelta atrás o backtracking

Descripción explicativa del esquema algorítmico de vuelta atrás o backtracking

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
15,074
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
470
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Búsqueda con retroceso
    • Introducción
    • El problema de las ocho reinas
    • El problema de la suma de subconjuntos
    • Coloreado de grafos
    • Ciclos hamiltonianos
    • Atravesar un laberinto
    • El problema de la mochila 0-1
  • 2. Búsqueda con retroceso: Introducción
    • Problemas que consideraremos:
      • Problemas de Decisión: Búsqueda de las soluciones que satisfacen ciertas restricciones.
      • Problemas de Optimización: Búsqueda de la mejor solución en base a una función objetivo.
      • Cada solución es el resultado de una secuencia de decisiones .
      • En algunos problemas de este tipo se conoce un criterio óptimo de selección en cada decisión: técnica voraz .
      • En otros problemas se cumple el principio de optimalidad de Bellman y se puede aplicar la técnica de la programación dinámica .
      • Existen otros problemas en los que no hay más remedio que buscar .
  • 3.
    • Planteamiento del problema:
      • Se trata de hallar todas las soluciones que satisfagan un predicado Sol .
      • La solución debe poder expresarse como una tupla ( x 1 ,…, x n ) donde cada x i pertenece a un dominio C i .
      • Si | C i |= t i , entonces hay
      • n -tuplas candidatas para satisfacer Sol .
      • Método de fuerza bruta : examinar las t n -tuplas y seleccionar las que satisfacen Sol .
      • Búsqueda con retroceso ( backtracking , en inglés): formar cada tupla de manera progresiva, elemento a elemento, comprobando para cada elemento x i añadido a la tupla que ( x 1 ,…, x i ) puede conducir a una tupla completa satisfactoria.
    Búsqueda con retroceso: Introducción
  • 4.
      • Deben existir unas funciones objetivo parciales o predicados acotadores Completable ( x 1 ,…, x i ).
      • Dicen si ( x 1 ,…, x i ) puede conducir a una solución.
      • Diferencia entre fuerza bruta y búsqueda con retroceso:
        • si se comprueba que ( x 1 ,…, x i ) no puede conducir a ninguna solución, se evita formar las t i +1  t n tuplas que comienzan por ( x 1 ,…, x i )
      • Para saber si una n -tupla es solución, suele haber dos tipos de restricciones:
        • explícitas: describen el conjunto C i de valores que puede tomar x i (todas las tuplas que satisfacen estas restricciones definen un espacio de soluciones posibles );
        • implícitas: describen las relaciones que deben cumplirse entre los x i (qué soluciones posibles satisfacen el predicado objetivo Sol ).
    Búsqueda con retroceso: Introducción
  • 5.
    • Ejemplo : el problema de las ocho reinas
      • El problema consiste en colocar ocho reinas en un tablero de ajedrez sin que se den jaque (dos reinas se dan jaque si comparten fila, columna o diagonal).
    Búsqueda con retroceso: Introducción 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
  • 6.
      • Formulación 1 :
      • Formulación 2 : Puesto que no puede haber más de una reina por fila, podemos replantear el problema como: “colocar una reina en cada fila del tablero de forma que no se den jaque”. En este caso, para ver si dos reinas se dan jaque basta con ver si comparten columna o diagonal.
      • Por lo tanto, toda solución del problema puede representarse con una 8-tupla ( x 1 ,…, x 8 ) en la que x i es la columna en la que se coloca la reina que está en la fila i del tablero.
      •  El espacio de soluciones consta de 8 8 8-tuplas   (16.777.216 8-tuplas)
      • Formulación 3: Puesto que no puede haber más de una reina por columna, sólo hace falta que consideremos las 8-tuplas ( x 1 ,…, x 8 ) que sean permutaciones de (1,2,...,8)
        •  El espacio de soluciones consta de 8! 8-tuplas   (40.320 8-tuplas)
    Búsqueda con retroceso: Introducción 64 8        4 . 426 . 165 . 368
  • 7.
    • Volviendo al planteamiento general:
      • Para facilitar la búsqueda, se adopta una organización en árbol del espacio de soluciones.
    • En el ejemplo, con la 2ª formulación y para el problema de las cuatro reinas (en un tablero 4  4):
    Búsqueda con retroceso: Introducción
  • 8. Búsqueda con retroceso: Introducción algoritmo BackTracking( ent k:entero; entsal X: vector [1..n] de valor) {Pre: X[1..k-1] es completable}   variable v:valor para todo v en C i hacer X[k]:=v; si completable(X,k) entonces si Sol(X,k) entonces guardar(X,k) fsi ; si k<n entonces BackTracking(k+1,X) fsi ; fsi fpara La llamada inicial es: ... BackTracking(1,X); ...
  • 9.
    • Nótese que el árbol no se construye explícitamente sino implícitamente mediante las llamadas recursivas del algoritmo de búsqueda.
    • El algoritmo no hace llamadas recursivas cuando:
      • k = n +1, o cuando
      • el nodo generado no es completable (PODA).
    • Backtracking : búsqueda primero en profundidad (DFS) en un árbol y con detección de soluciones parciales no completables (poda)
    • El algoritmo anterior halla todas las soluciones y además éstas pueden ser de longitud variable (< n+1).
    Búsqueda con retroceso: Introducción
  • 10.
    • Variantes:
      • Limitar el número de soluciones a una sola añadiendo un parámetro booleano de salida que indique si se ha encontrado una solución.
      • Forzar a que sólo los nodos hoja puedan significar solución (realizando la recursión sólo si no se ha encontrado un nodo solución):
      • Resolver problemas de optimización: además de la solución actual en construcción hay que guardar la mejor solución encontrada hasta el momento. Se mejora la eficiencia de la búsqueda si el predicado “completable” permiten eliminar los nodos de los que se sabe que no pueden llevar a una solución mejor que la ahora disponible ( poda ; métodos de ramificación y acotación ).
    Búsqueda con retroceso: Introducción
  • 11.
    • Sobre la eficiencia:
      • Depende de:
        • el número de nodos del árbol de búsqueda que se visitan: v ( n )
        • el trabajo realizado en cada nodo (normalmente un polinomio): p ( n )
          • Coste de: Completable y Sol
        • en general: O( p(n) v(n ))
      • Mejoras:
        • Si se consigue que los predicados acotadores reduzcan mucho el número de nodos generados (aunque un buen predicado acotador precisa mucho tiempo de evaluación; compromiso…)
          • Si lo reducen a un solo nodo generado (solución voraz ): O ( p ( n )  n ) nodos a generar en total
          • Normalmente:
            • O ( p ( n )  2 n ) ó O ( p ( n )  n!)
    Búsqueda con retroceso: Introducción
  • 12. El problema de la suma de subconjuntos
    • Problema:
      • Dados un conjunto W ={ w 1 ,…, w n } de n números positivos y otro número positivo M , se trata de encontrar todos los subconjuntos de W cuya suma es M .
      • Ejemplo: si W ={11,13,24,7} y M =31, entonces la solución es {11,13,7} y {24,7}.
    • Primera representación de la solución:
      • La solución puede representarse simplemente con los índices de los elementos de W .
      • En el ejemplo: (1,2,4) y (3,4).
      • En general, todas las soluciones son k -tuplas ( x 1 , x 2 ,…, x k ), 0< k < n+1 .
      • Restricciones sobre las soluciones:
        • Explícitas:
        • Implicitas:
  • 13.
    • Segunda representación de la solución:
      • Cada solución puede representarse con una n -tupla ( x 1 , x 2 ,…, x n ), tal que x i  {0,1}, 1≤ i ≤ n , de forma que:
        • x i = 0 si w i no se elige y
        • x i = 1 si w i se elige.
      • En el ejemplo anterior: (1,1,0,1) y (0,0,1,1).
    • Conclusión:
      • Pueden existir varias formas de formular un problema, con distintas representaciones de las soluciones (aunque siempre verificando éstas un conjunto de restricciones explícitas e implícitas).
      • En el problema que consideramos, ambas representaciones nos llevan a un espacio de estados que consta de 2 n tuplas.
    El problema de la suma de subconjuntos
  • 14.
    • Arbol del espacio de soluciones ( n =4) para la primera representación (tuplas de tamaño variable):
      • Un arco del nivel i al nivel i +1 representa un valor para x i .
      • El espacio de soluciones está definido por todos los caminos desde la raíz hasta cualquier hoja del árbol.
    El problema de la suma de subconjuntos 16 13 12 6 7 8 2 1 x 1 =1 x 2 =2 x 2 =3 x 2 =4 14 15 10 9 3 4 5 x 1 =2 x 1 =3 x 1 =4 11 x 2 =3 x 2 =4 x 2 =4 x 3 =3 x 3 =4 x 3 =4 x 3 =4 x 4 =4
  • 15.
    • Arbol del espacio de soluciones ( n =4) para la segunda representación (tuplas de tamaño fijo):
      • Los arcos del nivel i al nivel i +1 están etiquetados con el valor de x i (1 ó 0).
      • Todos los caminos desde la raíz a una hoja definen el espacio de soluciones (2 4 hojas que representan las 16 posibles 4-tuplas).
    El problema de la suma de subconjuntos 1 x 1 =1 30 31 28 29 24 25 22 23 16 17 14 15 10 11 8 9 26 27 20 21 12 13 6 7 18 19 4 5 2 3 x 1 =0 x 2 =1 x 2 =0 x 2 =1 x 2 =0 x 3 =1 x 3 =0 x 3 =1 x 3 =0 x 3 =1 x 3 =0 x 3 =1 x 3 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0
  • 16.
    • Estudiemos una solución de búsqueda con retroceso basada en la segunda representación (tuplas de tamaño fijo).
      • El elemento x[i] del vector solución toma el valor 1 ó 0 dependiendo de si el número w[i] se incluye o no en la solución.
      • Función acotadora (completable) :
      • La tupla (x[1],…x[k]) sólo puede conducir a una solución si:
      • Además la tupla (x[1],…x[k]) no puede conducir a una solución si:
      • Es decir, una función acotadora es:
    El problema de la suma de subconjuntos
  • 17. El problema de la suma de subconjuntos algoritmo sumasub( ent s,k,r:entero; entsal X: vector[1..n]de nat) {k: siguiente variable a decidir Los w[j] están en orden creciente s= w[j]*x[j]; r= w[j] s+w[k]  M; s+ w[i]  M } X[k]:=1; si s+w[k]=M entonces escribir(X[1..k]) sino si s+w[k]+w[k+1]  M entonces sumasub(s+w[k],k+1,r-w[k],X) fsi fsi si (s+r-w[k]  M) y (s+w[k+1]  M) entonces X[k]:=0; sumasub(s,k+1,r-w[k],X) fsi fin
  • 18.
      • La llamada inicial es:
      • Nótese que el algoritmo evita calcular
      • cada vez guardando esos valores en s y r.
      • A esto se le llama MARCAJE.
      • Coste:
        • con marcaje: O (2 n )
        • sin marcaje: O ( n 2 n )
    El problema de la suma de subconjuntos ... sumasub(0,1, w[i]) ...
  • 19. El problema de la suma de subconjuntos
      • Ejemplo: n =6, M =30, W =(5,10,12,13,15,18)
      • Los rectángulos son s , k , r en cada llamada.
      • A=(1,1,0,0,1); B=(1,0,1,1); C=(0,0,1,0,0,1).
      • Se construyen 26 nodos (del total de 2 7 -1=127)
    15,5,33 12,6,18 13,6,18 0,4,46 0,5,33 13,5,33 12,5,33 12,4,46 0,3,58 10,5,33 10,4,46 10,3,58 0,2,68 20,6,18 5,5,33 5,4,46 17,4,46 5,3,58 15,4,46 27,4,46 15,3,58 5,2,68 0,1,73 A C B x[1]=1 x[2]=1 x[3]=1 x[3]=0 x[4]=0 x[5]=1 x[2]=0 x[3]=1 x[3]=0 x[4]=1 x[4]=0 x[5]=1
  • 20. Coloreado de grafos
    • Problema de decisión:
      • Dados un grafo G y un número entero positivo m , ¿es G m -coloreable ?
      • Es decir, ¿se puede pintar con colores los nodos de G de modo que no haya dos vértices adyacentes con el mismo color y se usen sólo m colores?
    • Problema de optimización:
      • Dado un grafo G , ¿cuál es su número cromático ?
      • Es decir, ¿cuál es el menor número m de colores con el que se puede colorear G ?
  • 21.
    • Un subproblema muy famoso:
      • Dado un mapa, ¿pueden pintarse sus regiones (autonomías, países, o lo que sea) de tal forma que no haya dos regiones adyacentes de igual color y no se empleen más de 4 colores?
      • Cada región se modela con un nodo y si dos regiones son adyacentes sus correspondientes nodos se conectan con un arco.
      • Así se obtiene siempre un grafo “plano” (puede dibujarse en un plano sin cruzar sus arcos).
      • El mapa de la figura requiere 4 colores.
      • Desde hace muchos años se sabía que 5 colores eran suficientes para pintar cualquier mapa, pero no se había encontrado ningún mapa que requiriera más de 4.
      • Recientemente, después de varios cientos de años, se ha demostrado que 4 colores siempre son suficientes.
    Coloreado de grafos 1 2 3 4 5 5 4 3 1 2
  • 22.
    • El problema que consideraremos aquí:
      • Dado un grafo cualquiera, determinar todas las formas posibles en las que puede pintarse utilizando no más de m colores.
      • Representación elegida: matriz de adyacencias.
      • Justificación de la elección: sólo necesitaremos saber si un arco existe o no.
      • Representación de los colores: enteros de 1 a m .
      • Representación de la solución: vector de colores.
      • Espacio de estados para n =3 y m =3.
    Coloreado de grafos x[1]=1 x[1]=2 x[1]=3 x[2]=1 x[2]=2 x[2]=3 x[3]=1 x[3] =2 x[3]= 3
  • 23. Coloreado de grafos algoritmo m_col( ent k:entero; entsal X:vector[1..n]de nat) {Se usa una variable global g de tipo grafo.} para v:=1..m hacer X[k]:=v si completable(X,k) entonces si k=n entonces escribir(X) sino m_col(k+1,X) fsi fsi fpara fin funcion Completable( entsal x:sol; ent k:entero) variables b:booleano; j:entero b:=verdad; j:=1; mientras (j<k)  b hacer si g[k,j] y (x[k]=x[j]) entonces b:=falso sino j:=j+1 fsi fmientras retorna (b)
  • 24. Ciclos hamiltonianos
    • Problema: encontrar todos los ciclos hamiltonianos de un grafo.
      • Sea G =( V , A ) un grafo no dirigido, conexo con n vértices.
      • Un ciclo hamiltoniano es un camino que visita una vez cada vértice y vuelve al vértice inicial.
      • Es decir, v 1 v 2 … v n +1 tal que:
        • v i  V , i =1,…, n +1,
        • ( v i , v i +1 )  A , i =1,…, n ,
        • v 1 = v n +1 ,
        • v i  v j ,  i , j =1,…, n tales que i  j .
    • No se conoce un algoritmo eficiente para resolver el problema.
    • Nótese la relación entre el problema del cálculo de un hamiltoniano y el problema del viajante de comercio
  • 25.
    • Ejemplos:
      • Hamiltoniano: 1-2-8-7-6-5-4-3-1
      • No contiene ningún hamiltoniano.
    Ciclos hamiltonianos 8 1 2 3 4 5 6 7 5 1 2 3 4
  • 26.
    • Solución de búsqueda con retroceso:
      • En el vector solución ( x 1 ,…, x n ), x i representa el vértice visitado en i -ésimo lugar en el ciclo.
      • Cálculo de los posibles valores para x k si x 1 ,…, x k -1 ya tienen valores asignados:
        • k =1: x 1 puede ser cualquiera de los n vértices, pero para evitar escribir el mismo ciclo n veces obligamos que x 1 =1;
        • 1< k < n : x k puede ser cualquier vértice distinto de x 1 ,…, x k -1 y conectado por un arco con x k -1 .
        • k = n : x n sólo puede ser el vértice que queda sin visitar y debe estar conectado por sendos arcos con x 1 y x n -1 .
    Ciclos hamiltonianos
  • 27.
      • Grafo: matriz de adyacencias (sólo necesitaremos saber si un arco existe o no)
      • solución: vector de vértices.
    Ciclos hamiltonianos algoritmo hamiltoniano( ent k:entero; entsal X:vector[1..n] de nat) {Se usa una variable global g de tipo grafo.} para v:=1..n hacer X[k]:=v; si completable(k,X) entonces si k=n entonces escribir(X) sino hamiltoniano(k+1,X) fsi fsi fpara funcion completable( ent k:entero; ent X:vector[1..n] de nat) b:=g[X[k-1],X[k]]; para i:=1..k-1 mientras b hacer si X[i]=X[k] entonces b:=falso fsi fpara si k=n   g[X[n],X[1]] entonces b:=falso fsi retorna b x[1]:=1; hamiltoniano(2,x);
  • 28. Atravesar un laberinto
    • Problema:
      • Nos encontramos en una entrada de un laberinto y debemos intentar atravesarlo.
      • Representación: matriz de dimensión n  n de casillas marcadas como libre u ocupada por una pared.
      • Es posible pasar de una casilla a otra moviéndose sólamente en vertical u horizontal.
      • Se debe ir de la casilla (1,1) a la casilla ( n , n ).
  • 29.
      • Diseñaremos un algoritmo de búsqueda con retroceso de forma que se marcará en la misma matriz del laberinto un camino solución (si existe).
      • Si por un camino recorrido se llega a una casilla desde la que es imposible encontrar una solución, hay que volver atrás y buscar otro camino.
      • Además hay que marcar las casillas por donde ya se ha pasado para evitar meterse varias veces en el mismo callejón sin salida, dar vueltas alrededor de columnas…
    Atravesar un laberinto N M N N N N N N N N N N N N N N N N N N M M M M M M M M M M M M M M M M M N M N N M < < < < < < <
  • 30.
    • Estructura de datos:
    • Solución de búsqueda con retroceso:
    Atravesar un laberinto tipos casilla = (libre,pared,camino,imposible) laberinto = vector [1..n,1..n] de casilla funcion HayCamino( ent x,y:entero; entsal lab:laberinto) {Pre: Hemos encontrado un camino desde (1,1) hasta (x,y). Post: Devuelve cierto ssi se puede extender hasta (n,n)} ... HayCamino(1,1,lab) ...
  • 31. Atravesar un laberinto funcion HayCamino( ent x,y:entero; entsal lab:laberinto) {devuelve cierto ssi existe camino} si (x<1)  (x>n)  (y<1)  (y>n)  lab[x,y]  libre entonces devuelve falso sino lab[x,y]:=camino; si (x=n)  (y=n) entonces escribir(lab); devuelve cierto; sino b:= HayCamino(x+1,y,lab)  HayCamino(x,y+1,lab)  HayCamino(x-1,y,lab)  HayCamino(x,y-1,lab); si  b entonces lab[x,y]:= imposible; fsi devuelve b; fsi fsi fin
  • 32. El problema de la mochila 0-1
    • Recordar…
      • Se tienen n objetos y una mochila.
      • El objeto i tiene peso p i y la inclusión del objeto i en la mochila produce un beneficio b i .
      • El objetivo es llenar la mochila, de capacidad C , de manera que se maximice el beneficio.
    • Es el primer problema de optimización que vamos a resolver con Backtracking.
  • 33.
      • Tuplas de tamaño fijo:
      • x i =0 si el objeto i -ésimo no se introduce
      • x i =1 si el objeto se introduce
    El problema de la mochila 0-1 Elegimos ésta última representación. 1 x 1 =0 5 6 8 9 12 13 15 16 20 21 23 24 27 28 30 31 4 7 11 14 19 22 26 29 3 10 18 25 2 17 x 1 =1 x 2 =0 x 2 =1 x 2 =0 x 2 =1 x 3 =0 x 3 =1 x 3 =0 x 3 =1 x 3 =0 x 3 =1 x 3 =0 x 3 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1 x 4 =0 x 4 =1
  • 34.
    • Problema de optimización (maximización): Solo nos interesa la mejor solución
    • En todo momento guardamos el coste de la mejor solución encontrada hasta el momento MS (que es una cota inferior de la mejor solución)
    • Sólo buscaremos donde podamos mejorar respecto a la mejor solución (poda basada en la mejor solución, PBMS)
    El problema de la mochila 0-1
  • 35.
    • Formalmente:
      • Sea X[1.. k -1] la asignación en curso.
      • Sea ben el beneficio de la mejor solución que hemos encontrado en lo que llevamos de búsqueda (si aun no hemos encontrado ninguna ben =0)
      • c ( X , k ) es el beneficio de la “mejor” solución que se puede obtener extendiendo X [1.. k -1]
      • cota ( X , k ) es una cota superior de c ( X , k ). Es decir, cota ( X , k )  c ( X , k ), para todo X [1.. k -1]
      • Si cota ( X , k )  ben , entonces hacemos backtracking (podamos)
      • ¿cómo calcular cota ( X , k ) en el problema de la mochila?
        • relajar el requisito de integridad en las decisiones que aún no hemos hecho: x i  {0,1}, k  i  n se sustituye por 0  x i  1, k  i  n
        • aplicar el algoritmo voraz
    El problema de la mochila 0-1
  • 36. El problema de la mochila 0-1 función cota(benef,peso:vectReal; cap,ben:real; k:entero) devuelve real {cap=capacidad aún libre de la mochila; ben=beneficio actual; k=índice del primer objeto a considerar} principio si k>n or cap=0.0 entonces devuelve ben sino si peso[k]>cap entonces dev ben+cap/peso[k]*benef[k] sino dev cota(benef,peso,cap-peso[k], ben+benef[k],k+1) fsi fsi fin tipo vectReal= vector [1..n] de real {Pre:  i  1..n:peso[i]>0, benef[i]>0,  i  1..n-1:benef[i]/peso[i]  benef[i+1]/peso[i+1]}
  • 37. El problema de la mochila 0-1 tipo solución= vector [1..n] de 0..1 {variables globales: benef,peso:vectReal; cap:real} algoritmo búsqueda( ent solAct:solución; ent benAct,pesAct:real; ent k:entero; e/s sol:solución; e/s ben:real) para v:=1 hasta 0 hacer solAct[k]:=v; benAct:=benAct+v*benef[k]; pesAct:=pesAct+v*peso[k]; si pesAct  cap  ben<cota(benef,peso, cap-pesAct,benAct,k+1) entonces si k=n entonces si benAct>ben entonces sol:=solAct; ben:=benAct fsi sino búsqueda(solAct,benAct,pesAct, k+1,sol,ben) fsi fsi fpara fin
  • 38.
    • Mejora adicional:
      • encontrar una solucion factible (no necesariamente óptima) con un algoritmo voraz. Sea r su coste.
      • Obviamente r es una cota inferior de la solución del problema.
      • Por lo tanto, podemos inicializar ben := r
    • ejercicio: Pensar un algoritmo voraz que encuentre una solución factible.
    El problema de la mochila 0-1 algoritmo mochila01( ent benef,peso:vectReal; ent cap:real; sal sol:solución; sal ben:real) variables obj:entero; solAct:solución principio ben:=0.0; búsqueda(solAct,0.0,0.0,1,sol,ben) fin
  • 39.
    • Ejemplo:
      • benef=(11,21,31,33,43,53,55,65)
      • peso=(1,11,21,23,33,43,45,55)
      • cap=110
      • n=8
    El problema de la mochila 0-1 89 139 99 149 101 151 109 159 66 106 56 96 33 63 68 108 35 65 12 32 1 11 164.88 155.11 157.44 159.76 154.88 160.22 157.55 157.11 162.44 164.66 163.81 139 149 151 159 161.63 160.18 158 159.79 159.33 157.63 1 0 1 1 1 0 0 0 1 0 0 0 0 1 0 1 0 1 0 0 1 1 0 0 0 0 0 0 162 0 0 1 0 ben=159 sol=(1,1,1,0,1,1,0,0)
  • 40.
      • De los 2 9 -1 nodos del espacio de estados, sólo se generaron 33.
      • Se podía haber reducido a 26 simplemente sustituyendo la condición
      • ben < cota(...)
      • en el algoritmo “búsqueda” por:
      • ben <  cota(...) 
    El problema de la mochila 0-1
  • 41.
    • ahora para problemas de minimización
      • X [1.. k ]: asignación actual (solución que estamos tratando de construir)
      • MejorSol : Mejor solución encontrada hasta el momento (se inicializa a Null)
      • MS : Coste de la mejor solución encontrada hasta el momento (es una cota superior de la solución óptima). Se inicializa a infinito.
      • c’ ( X , k ): devuelve una cota inferior del mejor coste que se puede obtener a partir de la asignación actual
      • Si c’ ( X , k )  MS , entonces no sirve de nada seguir con la asignación actual (podamos, es decir, hacemos backtracking)
      • Es decir, sólo hacemos llamada recursiva si: completable ( X , k ) y c’ ( X , k )< MS
    Backtracking genérico para problemas de optimización
  • 42. Backtracking genérico para problemas de optimización algoritmo BackTracking( ent k:entero; entsal X: vector [1..n] de valor) {Pre: X[1..k-1] es completable, c’(X,k-1)<MS}   para todo v en C i hacer X[k]:=v; si (completable(X,k)  c’(X,k)<MS) entonces si Sol(X,k) entonces MejorSol:= X; MS:= Coste(X) fsi ; si k<n entonces BackTracking(k+1,X) fsi ; fsi fpara
  • 43.
    • Arboles dinámicos:
      • Hasta ahora hemos considerado árboles de búsqueda estáticos:
        • siguiendo cualquier rama nos encontrábamos las variables en el mismo orden.
        • recorriendo un nivel de izquierda a derecha nos encontrábamos los valores en el mismo orden
      • Arboles dinámicos: ordenes variables
    • Anticipación (look ahead):
      • Cada variable x i guarda la lista de los valores de su dominio C i
      • Cada vez que se asigna un valor a una variable, se eliminan de todas las variables no asignadas los valores incompatibles con la asignación
      • Si a alguna variable no le quedan valores posibles, BACKTRACKING
    • Eliminación de simetrías:
      • En muchos problemas reales existen simetrías que hacen que varias soluciones sean esencialmente la misma (via rotaciones, proyecciones,...)
      • Encontrar la misma solución varias veces es ineficiente
      • Solución: añadir nuevas restricciones que prohiban soluciones repetidas
    Mejoras al esquema de Backtracking
  • 44.
    • Vamos a desarrollar un backtracking para las n-reinas que introduzca estas mejoras:
      • X: vector[1..n] de nat
        • x[i]=0, la columna i, aun no tiene reina asignada
        • x[i]= j (j<>0), la reina de la columna i esta situada en la fila j
      • tipo dominios es vector[1..n] de lista de nat
        • Si L es una variable de tipo dominios,
        • L[i] es la lista de los valores posibles para la variable x[i]
        • Inicialmente:
        • L[i]={1,2,...,n} para i=2..n
        • L[1]={1,2,...,  n/2  } (para eliminar simetrías)
    Mejoras al esquema de Backtracking
  • 45. N- reinas algoritmo n-reinas( ent k:entero; ent L:dominios; entsal X:vector[1..n]de nat) {k: numero de variables asignadas, X: asignación actual L: valores compatibles con la asignación actual} L2:=L i:=Seleccionar_Variable(X,L); {selección arbitraria} para v  L[i] hacer {orden arbitrario} X[i]:=v; si anticipación(X,i,v,L2) entonces si k=n entonces escribir(X) sino n-reinas(k+1,L2,X) fsi fsi L2:=L; fpara X[i]:=0; fin
  • 46.
    • Para n-reinas:
      • seleccionar la variable a la que le queden menos valores
      • asignar los valores en orden aleatorio
    N- reinas funcion anticipacion( ent X:sol; ent i,v:entero; entsal L2:dominios) variables b:booleano; j:entero b:=cierto; j:=1; mientras (j<n+1)  b hacer si X[j]=0 entonces para u  L[j] hacer si u=v  |i-j|=|u-v| entonces borrar(L[j],v) fpara b:=falso sino j:=j+1 fsi fmientras retorna (b)