46
squeda con retroceso Pág. 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

Back Tracking

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Back Tracking

Búsqueda con retroceso Pág. 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

Page 2: Back Tracking

Búsqueda con retroceso Pág. 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.

Page 3: Back Tracking

Búsqueda con retroceso Pág. 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 (x1,…,xn) donde cada xi pertenece a un dominio Ci.

– Si |Ci|=ti, 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 xi añadido a la tupla que (x1,…,xi) puede conducir a una tupla completa satisfactoria.

Búsqueda con retroceso:

Introducción

t ti

i 1

n

Page 4: Back Tracking

Búsqueda con retroceso Pág. 4

– Deben existir unas funciones objetivo parciales o predicados acotadores Completable(x1,…,xi).

Dicen si (x1,…,xi) puede conducir a una solución.

– Diferencia entre fuerza bruta y búsqueda con retroceso:

si se comprueba que (x1,…,xi) no puede conducir a ninguna solución, se evita formar las ti+1tn tuplas que comienzan por (x1,…,xi)

– Para saber si una n-tupla es solución, suele haber dos tipos de restricciones:

explícitas: describen el conjunto Ci de valores que puede tomar xi (todas las tuplas que satisfacen estas restricciones definen un espacio de soluciones posibles);

implícitas: describen las relaciones que deben cumplirse entre los xi (qué soluciones posibles satisfacen el predicado objetivo Sol).

Búsqueda con retroceso:

Introducción

Page 5: Back Tracking

Búsqueda con retroceso Pág. 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 8123

456

78

Page 6: Back Tracking

Búsqueda con retroceso Pág. 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 (x1,…,x8) en la que xi es la columna en la que se coloca la reina que está en la fila i del tablero.

El espacio de soluciones consta de 88 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 (x1,…,x8) 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

Page 7: Back Tracking

Búsqueda con retroceso Pág. 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 44):

Búsqueda con retroceso:

Introducción

Page 8: Back Tracking

Búsqueda con retroceso Pág. 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:valorpara todo v en Ci 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; fsifpara

algoritmo BackTracking(ent k:entero; entsal X:vector[1..n]de valor){Pre: X[1..k-1] es completable} variable v:valorpara todo v en Ci 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; fsifpara

La llamada inicial es:

...BackTracking(1,X);...

...BackTracking(1,X);...

Page 9: Back Tracking

Búsqueda con retroceso Pág. 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

Page 10: Back Tracking

Búsqueda con retroceso Pág. 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

Page 11: Back Tracking

Búsqueda con retroceso Pág. 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) 2n) ó O(p(n) n!)

Búsqueda con retroceso:

Introducción

Page 12: Back Tracking

Búsqueda con retroceso Pág. 12

El problema de la suma de subconjuntos

Problema:– Dados un conjunto W={w1,…,wn} 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(x1,x2,…,xk), 0<k<n+1.

– Restricciones sobre las soluciones: Explícitas:

Implicitas:

xi j j es un entero y 1 j n

i j xi xj

wxii 1

k

M

xi xi 1, 1i n

Page 13: Back Tracking

Búsqueda con retroceso Pág. 13

Segunda representación de la solución:

– Cada solución puede representarse con una n-tupla (x1,x2,…,xn), tal que xi {0,1}, 1≤i≤n,

de forma que: xi = 0 si wi no se elige y xi = 1 si wi 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 2n tuplas.

El problema de la suma de subconjuntos

Page 14: Back Tracking

Búsqueda con retroceso Pág. 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 xi.

– 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

1312

6 7 8

2

1

x1=1

x2=2x2=3

x2=4

14 15

10 9

3 4 5

x1=2x1=3

x1=4

11

x2=3

x2=4 x2=

4

x3=3

x3=4

x3=4

x3=4

x4=4

Page 15: Back Tracking

Búsqueda con retroceso Pág. 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 xi (1 ó 0).

– Todos los caminos desde la raíz a una hoja definen el espacio de soluciones (24 hojas que representan las 16 posibles 4-tuplas).

El problema de la suma de subconjuntos

1

x1=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

x1=0

x2=1 x2=0 x2=1 x2=0

x3=1 x3=0 x3=1 x3=0 x3=1 x3=0 x3=1 x3=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

x4=1x4=0

Page 16: Back Tracking

Búsqueda con retroceso Pág. 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]) nopuede conducir a una solución si:

– Es decir, una función acotadora es:

El problema de la suma de subconjuntos

Page 17: Back Tracking

Búsqueda con retroceso Pág. 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) fsifin

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) fsifin

j=1k-1 j=k

n i=1

n

Page 18: Back Tracking

Búsqueda con retroceso Pág. 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(2n)

sin marcaje: O(n 2n)

El problema de la suma de subconjuntos

w[i ]x[i ] y w[i ]i=k+1ni=1

k

... sumasub(0,1, w[i]) ...

... sumasub(0,1, w[i]) ...

i=1n

Page 19: Back Tracking

Búsqueda con retroceso Pág. 19

El problema de la suma de subconjuntos

15,5,33

12,6,18 13,6,18

0,4,46

0,5,3313,5,3312,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,4617,4,46

5,3,58

15,4,4627,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

– 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 27-1=127)

Page 20: Back Tracking

Búsqueda con retroceso Pág. 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?

Page 21: Back Tracking

Búsqueda con retroceso Pá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

54

3

1

2

Page 22: Back Tracking

Búsqueda con retroceso Pág. 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]=1x[1]=2 x[1]=3

x[2]=1x[2]=2

x[2]=3

x[3]=1

x[3]=2

x[3]= 3

Page 23: Back Tracking

Búsqueda con retroceso Pág. 23

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 fparafin

funcion Completable(entsal x:sol; ent k:entero) variables b:booleano; j:enterob:=verdad; j:=1;mientras (j<k) b hacer si g[k,j] y (x[k]=x[j]) entonces b:=falso sino j:=j+1 fsifmientrasretorna(b)

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 fparafin

funcion Completable(entsal x:sol; ent k:entero) variables b:booleano; j:enterob:=verdad; j:=1;mientras (j<k) b hacer si g[k,j] y (x[k]=x[j]) entonces b:=falso sino j:=j+1 fsifmientrasretorna(b)

Coloreado de grafos

Page 24: Back Tracking

Búsqueda con retroceso Pág. 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, v1v2…vn+1 tal que: viV, i=1,…,n+1, (vi,vi+1)A, i=1,…,n, v1=vn+1, vivj, 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

Page 25: Back Tracking

Búsqueda con retroceso Pág. 25

Ejemplos:

Hamiltoniano: 1-2-8-7-6-5-4-3-1

No contiene ningún hamiltoniano.

Ciclos hamiltonianos

8

1 2 3 4

567

5

1 2 3

4

Page 26: Back Tracking

Búsqueda con retroceso Pág. 26

Solución de búsqueda con retroceso:

– En el vector solución (x1,…,xn), xi representa el vértice visitado en i-ésimo lugar en el ciclo.

– Cálculo de los posibles valores para xk si x1,…,xk-1 ya tienen valores asignados:

k=1: x1 puede ser cualquiera de los n vértices, pero para evitar escribir el mismo ciclo n veces obligamos que x1=1;

1<k<n: xk puede ser cualquier vértice distinto de x1,…,xk-1 y conectado por un arco con xk-1.

k=n: xn sólo puede ser el vértice que queda sin visitar y debe estar conectado por sendos arcos con x1 y xn-1.

Ciclos hamiltonianos

Page 27: Back Tracking

Búsqueda con retroceso Pág. 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 fsifpara

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 fsifpara

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 fsifparasi k=n g[X[n],X[1]] entonces b:=falso fsiretorna b

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 fsifparasi k=n g[X[n],X[1]] entonces b:=falso fsiretorna b

x[1]:=1;hamiltoniano(2,x);

x[1]:=1;hamiltoniano(2,x);

Page 28: Back Tracking

Búsqueda con retroceso Pág. 28

Atravesar un laberinto

Problema:– Nos encontramos en una entrada de un

laberinto y debemos intentar atravesarlo.

– Representación: matriz de dimensión nn 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).

Page 29: Back Tracking

Búsqueda con retroceso Pág. 29

– Diseñaremos un algoritmode 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

NN

NN

N NN N

NN

NN

NN

N N N

MM

M

M MM M

MM M

MMM

MM

M M

N M N

NM

< <<<

< <<

Page 30: Back Tracking

Búsqueda con retroceso Pág. 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

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)}

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)...

...HayCamino(1,1,lab)...

Page 31: Back Tracking

Búsqueda con retroceso Pág. 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 fsifin

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 fsifin

Page 32: Back Tracking

Búsqueda con retroceso Pág. 32

El problema de la mochila 0-1

Recordar…– Se tienen n objetos y una mochila.

– El objeto i tiene peso pi y la inclusión del objeto i en la mochila produce un beneficio bi.

– 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.

maximizar bixi1i n

sujeto a pixi1i n C

con xi {0,1}, bi 0, pi 0, 1i n

Page 33: Back Tracking

Búsqueda con retroceso Pág. 33

– Tuplas de tamaño fijo:

xi=0 si el objeto i-ésimo no se introduce

xi=1 si el objeto se introduce

El problema de la mochila 0-1

1

x1=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

x1=1

x2=0 x2=1 x2=0 x2=1

x3=0 x3=1 x3=0 x3=1 x3=0 x3=1 x3=0 x3=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

x4=0x4=1

Elegimos ésta última representación.

Page 34: Back Tracking

Búsqueda con retroceso Pág. 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

Page 35: Back Tracking

Búsqueda con retroceso Pág. 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:xi{0,1}, ki n se sustituye por 0xi

1, kin aplicar el algoritmo voraz

El problema de la mochila 0-1

Page 36: Back Tracking

Búsqueda con retroceso Pág. 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 fsifin

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 fsifin

tipo vectReal=vector[1..n] de realtipo vectReal=vector[1..n] de real

{Pre: i1..n:peso[i]>0, benef[i]>0, i1..n-1:benef[i]/peso[i]benef[i+1]/peso[i+1]}

Page 37: Back Tracking

Búsqueda con retroceso Pág. 37

El problema de la mochila 0-1

tipo solución=vector[1..n] de 0..1tipo 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 pesActcap 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 fsifparafin

{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 pesActcap 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 fsifparafin

Page 38: Back Tracking

Búsqueda con retroceso Pág. 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.

algoritmo mochila01(ent benef,peso:vectReal; ent cap:real; sal sol:solución; sal ben:real)variables obj:entero; solAct:soluciónprincipio ben:=0.0; búsqueda(solAct,0.0,0.0,1,sol,ben)fin

algoritmo mochila01(ent benef,peso:vectReal; ent cap:real; sal sol:solución; sal ben:real)variables obj:entero; solAct:soluciónprincipio ben:=0.0; búsqueda(solAct,0.0,0.0,1,sol,ben)fin

El problema de la mochila 0-1

Page 39: Back Tracking

Búsqueda con retroceso Pág. 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

89139

99149

101151

109159

66106

56 96

33 63

68108

35 65

12 32

1 11

164.88

155.11

157.44

159.76

154.88160.22

157.55

157.11162.44

164.66

163.81

139149 151 159

161.63

160.18158

159.79 159.33

157.63

1 0

1

1

1

0

0

0

1 0

0

0

0

1 0

1 0

1 001

1 0

00

0

0

0

1620

0 1

0

ben=159sol=(1,1,1,0,1,1,0,0)

Page 40: Back Tracking

Búsqueda con retroceso Pág. 40

– De los 29-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

Page 41: Back Tracking

Búsqueda con retroceso Pág. 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

Page 42: Back Tracking

Búsqueda con retroceso Pág. 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 Ci 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; fsifpara

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 Ci 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; fsifpara

Page 43: Back Tracking

Búsqueda con retroceso Pág. 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 xi guarda la lista de los valores de su

dominio Ci

– 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

Page 44: Back Tracking

Búsqueda con retroceso Pág. 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

Page 45: Back Tracking

Búsqueda con retroceso Pág. 45

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

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

N- reinas

Page 46: Back Tracking

Búsqueda con retroceso Pág. 46

Para n-reinas:– seleccionar la variable a la que le queden

menos valores – asignar los valores en orden aleatorio

funcion anticipacion(ent X:sol; ent i,v:entero; entsal L2:dominios) variables b:booleano; j:enterob:=cierto; j:=1;mientras (j<n+1) b hacer si X[j]=0 entonces para uL[j] hacer si u=v |i-j|=|u-v| entonces borrar(L[j],v) fpara b:=falso sino j:=j+1 fsifmientrasretorna(b)

funcion anticipacion(ent X:sol; ent i,v:entero; entsal L2:dominios) variables b:booleano; j:enterob:=cierto; j:=1;mientras (j<n+1) b hacer si X[j]=0 entonces para uL[j] hacer si u=v |i-j|=|u-v| entonces borrar(L[j],v) fpara b:=falso sino j:=j+1 fsifmientrasretorna(b)

N- reinas