f[i-1][j-p[i]]+v[i]) f[i][j]=f[i-1][j]; else f[i][j]=f[i-1][j-p[i]]+v[i]; return;
s a c i n c é T e d
s i s i l á n A
}
Metodología y Tecnología Tecnología de la Programación II
50
El Problema de la Mochila Entera Ejemplo s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Supongamos que tenemos 5 objetos con pesos p[0]=5, p[1]=4, p[2]=2, p[3]=3, p[4]=4, y valores v[0]=20, v[1]=15, v[2]=10, v[3]=12, v[4]=14, entonces, si el peso máximo de la mochila es 10, la función anterior generaría la siguiente tabla: Peso Objeto Objeto Objeto Objeto Objeto
0 0 1 2 3 4
1 0 0 0 0 0
0 0 0 0 0
2
3
4
0 0 10 10 10
0 0 10 12 12
0 15 15 15 15 15
5 6 7 8 9 10 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 35 35 35 35 20 25 30 30 35 35 22 25 30 32 37 42 22 25 30 32 37 42
Valor máximo de la mochila
Metodología y Tecnología Tecnología de la Programación II
51
El Problema de la Mochila Entera Algoritmo Programación Programación Dinámica Dinámica s f El valor máximo de la mochila será f[n,pmax]. a c i m f Por otro lado, los objetos incluidos en la mochila t í r solución óptima pueden obtenerse mediante la función o g l void ob void obje jeto tos( s(in int t n, n,in int t v[ v[n] n],i ,int nt p[ p[n] n],i ,int nt pm pmax ax, , A
en la
int f[ int f[n] n][p [pma max] x],i ,int nt so sol[ l[n] n]){ ){ for fo r (int i=n i=n-1; -1;i> i>0;i 0;i--) --) if (p[i]>pmax) sol[i]=0; else if (f[i-1][pmax-p[i]]+v[i]>f[i-1][pmax]){ sol[i]=1; pmax-=p[i]; pmax-=p[i] ; } else sol[i]=0; if (p[0]
s a c i n c é T e d
s i s i l á n A
}
Metodología y Tecnología Tecnología de la Programación II
52
El Problema de la Mochila Entera Coste Temporal Cada componente de la tabla se calcula en un tiempo O(np npmax). constante, luego la construcción de la tabla es O( Por otro lado, la función que determina los objetos introducidos en la mochila a partir de la tabla, sólo tiene un bucle que recorre todos los objetos para ver si están o no dentro de la mochila. Como el cuerpo del bucle tiene un coste constante, su coste es O( O(n n). f Así pues, el coste total es O( O(np npmax) + O(n O(n) = O(np O(npmax). pmax≥n) sería un f Se observa que si pmax es muy grande ( p coste cuadrático o superior, por lo que no sería muy eficiente. f Por último, hay que notar que si los pesos no fuesen enteros, el algoritmo no valdría.
s f a c i m t í r f o g l A
s a c i n c é T e d
s i s i l á n A
Metodología y Tecnología Tecnología de la Programación II
53
El Problema del Viajante s f a c i m t í r f o g l A f
s a c i n c é T e d
Un viajante tiene que recorrer n ciudades y regresar a la ciudad de partida, sin pasar dos veces por la misma ciudad. Se supone que los caminos son unidireccionales y se conoce la distancia de cada camino. ¿Cuál es recorrido que debe seguir para que sea lo más corto posible?
%
6
3
4 2
s i s i l á n A
3
2 2
%
5 3
4 6
Metodología y Tecnología Tecnología de la Programación II
%0
?
% 1
5 54
El Problema del Viajante Modelizac Mode lización ión Medi Mediante ante Graf Grafos os Modeliza Modelización ción s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á f n A
Si representamos cada ciudad mediante un nodo de un grafo y cada camino como una arista dirigida, tendremos un grafo =(V,A V,A)) donde dirigido G=( – V ={1,…,n ={1,…,n} es el conjunto de vértices (ciudades). – A es el conjunto de aristas (i j) ,j) con i j ,j ∈ V (caminos). – D(i j) , j) es la longitud de (i j) ,j) si (i j) , j) ∈ A, o ∞ si (i j) ,j) ∉ A. De\A 0 1 2 3 0 ∞ 3 ∞ 3 1 5 ∞ 4 ∞ 2 2 6 ∞ 6 3 2 5 4 ∞
Se trata de un problema de búsqueda en un grafo del ciclo Hamiltonia Hamil toniano no de longitud longitud mínima. mínima.
Metodología y Tecnología Tecnología de la Programación II
55
El Problema del Viajante s f a c i m t í r o g l A
s a c i n c é T e d
f
f
Suponiendo que la ciudad de partida es la 0, si llamamos C (i,W ) a la longitud del camino mínimo de i a 0 que pasa por todos los vértices de W ⊂ V , siendo 0∉W , entonces si W = ∅ D (i,0) C (i,W ) = ( D (i, j ) + C ( j ,W − { j})) si W ≠ ∅ min j∈W Como la ciudad de partida es la 0, la solución al problema será C (0,V (0,V -{0}) -{0}). Se cumple el principio de optimalidad.
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
56
El Problema del Viajante Algoritmo Recursivo Recursivo (Fuerza Bruta) Bruta) s f La siguiente función en C++ implementa la función anterior a c i de manera recursiva m t í r float floa t c(in c(int t n, n,in int t i, i,co cons nst t conj conjun unto to &w &w,f ,flo loat at **d **d){ ){ o g conj co njun unto to cw cw(w (w); ); l A
cw.eliminar(i); if (cw.vacio()) return d[i][0]; float dist,dmin=DMAX; for(i fo r(int nt j= j=0;j 0;j
s a c i n c é T e d
s i s i l á n A
Metodología y Tecnología Tecnología de la Programación II
57
El Problema del Viajante Algoritmo Recursivo Recursivo (Fuerza Bruta) Bruta) s f Siendo la interfaz de la clase conjunto la siguiente a c i class clas s co conj njun unto to{ { m t í private: r o int nume numel; l; // Cardinal Cardinal del del conjunto conjunto univers universal al g l A bool elementos elementos[]; []; // Vector Vector de pertenencia pertenencia a conjunto
public: conjunto con junto(int (int n); // Inic Iniciali ializa za al conj conjunto unto vac vacio io conjunto(const conjunto( const conjunto &a); // // Constructor Constructor de copia void vo id ani aniad adir( ir(int int i); i);// // Añad Añade e el el elem element ento o i void vo id eli elimi minar nar(in (int t i) i);// ;// Eli Elimin mina a el elem element ento o i bool pertenece pertenece(int (int i); // Pertenencia Pertenencia de i int card cardinal inal(); (); // Cardin Cardinal al del conjun conjunto to bool vacio(); // Comprueba Comprueba si el conjunto conjunto está está vacio };
s a c i n c é T e d
s i s i l á n A
f
Y DMAX una constante con un valor alto para simular ∞.
Metodología y Tecnología Tecnología de la Programación II
58
El Problema del Viajante Coste del Algoritmo de Fuerza Bruta s f a c i m t í r o g l A
Esta función estudia todos los posibles caminos por fuerza bruta 0 Origen 3
4 s a c i n c é T e d
s i s i l á n A
1
∞
6
2 6
3
3 2
f
2 2
2
6
5
1 ∞
4
3
∞
3 5
3 2
1ª visita
4
1 4
1 5
3
2
2ª visita
1
3ª visita
6
2 2
R e c o r r i d o
5
0
0
0
0
0
0
Destino
15
∞
∞
∞
14 Min
18
Distancia
El coste es O( O(n n!).
Metodología y Tecnología Tecnología de la Programación II
59
El Problema del Viajante Mejora de la eficiencia s f a c i m t í r f o g l A
s a c i n c é T e d
s i s i l á n A
f
f
La función anterior repite llamadas para calcular C (i,W ), y por tanto es ineficiente. Utilizando la técnica de programación dinámica, podemos guardar los valores de C (i,W ) en una tabla para evitar repetir su cálculo. Para indexar la tabla en la segunda dimensión, asignaremos un código único a cada subconjunto W para identificarlo. Puesto que el número de ciudades es n, el número de posibles subconjuntos es 2n. Si representamos cada subconjunto mediante un vector 0 si i ∉ w W = [ x0 ,..., xn−1 ] con xi = 1 si i ∈ w id(W W ) = x020 + x121 +…+ +…+ x xn-12n-1 asigna un código entonces, id( único a cada subconjunto.
Metodología y Tecnología Tecnología de la Programación II
60
El Problema del Viajante Algoritmo Programación Programación Dinámica Dinámica s f La siguiente función en C++ calcula la distancia a c i utilizando programación dinámica m t í r float floa t dis dist_ t_mi min( n(in int t n, n,in int t i, i,co cons nst t con conju junt nto o &w &w, , o g float **d,float **c){ l A
mínima
conjunto cw(w conjunto cw(w); ); cw.e cw.elimi liminar( nar(i); i); if (cw.vacio()) return d[i][0]; if (c[i][cw.id()]>0) return c[i][cw.id()]; float dist,dmin=DMAX; for(i fo r(int nt j= j=0;j 0;j
s a c i n c é T e d
s i s i l á n A
}
Metodología y Tecnología Tecnología de la Programación II
61
El Problema del Viajante Construcción de la Tabla s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Para el ejemplo anterior, con D(i,j) De\A 0 1 2 3 0 ∞ 3 ∞ 3 1 5 ∞ 4 ∞ 2 2 6 ∞ 6 3 2 5 4 ∞
la tabla de distancias mínimas resultante C (i,W ) es i\W 0 1 2 3
0 -1 -1 -1 -1
1 -1 -1 -1 -1 -1 -1 -1 -1
2 -1 -1 11 11 10 10
3 4 -1 -1 -1 -1 -1 6 -1 -1 -1 -1 -1 6
Metodología y Tecnología Tecnología de la Programación II
5 -1 -1 -1 -1 -1 -1 -1 -1
6 -1 -1 -1 11 11
7 -1 -1 -1 -1 -1 -1 -1 -1
8 9 -1 -1 -1 -1 ∞ -1 8 -1 -1 -1 -1 -1 -1
10 1 0 -1 -1 16 16 -1
11 -1 -1 -1 -1
12 -1 12 12 -1 -1
13 -1 -1 -1 -1
14 14 14 -1 -1 -1
15 -1 -1 -1 -1
62
El Problema del Viajante Coste de la Programación Dinámica s f a c i m t í r o g l A
El coste del algoritmo para completar la tabla C (i,W ) supone: =1,…,n n-1: n-1 consultas a tabla; – Cálculo de C (i,∅) para i=1,…, k = = Cardinal(W Cardinal(W ) ≤ n-2: – Cálculo de C (i,W ) para 1≤ k n − 2 k sumas; k
(n − 1) s a c i n c é T e d
f
s i s i l f á n A
(0,V ): n-1 sumas. – Cálculo C (0,V En total n −2 n − 2 2 n Θ 2(n − 1) + ∑ (n − 1) k k = Θ(n 2 ) k =1 que, aunque es exponencial, es de orden menor que O( O(n n!). El precio de esta mejora es el coste espacial de la tabla C (i,W ) que es Θ(n2n).
Metodología y Tecnología Tecnología de la Programación II
63
El Problema del Viajante Itinerario del Recorrido Mínimo s f El itinerario del recorrido mínimo podemos calcularlo a c i de la tabla C (i,W ) mediante la siguiente función m t í r void camino void camino_mi _min(i n(int nt n, n,con conju junto nto &w &w,fl ,float oat **d, **d, o g float flo at **c, **c,int int *ca *camin mino){ o){ l A
s a c i n c é T e d
s i s i l á n A
float dist float dist,dm ,dmin; in; int int jmi jmin; n; for fo r (int (int i=1 i=1;i< ;i
Metodología y Tecnología Tecnología de la Programación II
a partir
64
El Problema del Viajante Itinerario del Recorrido Mínimo s f a c i m t í r o g l A
Para el ejemplo, la función anterior devuelve el itinerario camino[4]={0,1,2,3}, es decir 3
%
6
3
4 s a c i n c é T e d
2
2 2
%
5 3
4 6
%0
%
5
1
s i s i l á n A
¡Que efectivamente es el camino de mínima longitud!
Metodología y Tecnología Tecnología de la Programación II
65
Vuelta Atrás (Backtrackin (Backtracking) g)) (Backtracking s f a c i m t í r o g l A
s a c i n c é T e d
f
s i s i l f á n A
La técnica de VUELTA ATRÁS es parecida a la técnica devoradora en que resuelve un problema de manera gradual tomando decisiones o realizando acciones que permiten ir construyendo progresivamente la solución del problema. Sin embargo, a diferencia de la técnica devoradora, las decisiones tomadas pueden volverse a reconsiderar si no se llega una solución aceptable u óptima. Básicamente, esta técnica comienza a resolver el problema buscando todas las soluciones posibles, como lo hace la técnica de fuerza bruta, pero cuando detecta que una solución parcial no puede llegar a ser óptima, la rechaza y no construye más soluciones a partir de ella. Se suele aplicar también a problemas de decisión u optimización con o sin restricciones, cuando no existe un criterio óptimo de toma de decisiones locales.
Metodología y Tecnología Tecnología de la Programación II
66
Recordemos los Elementos de un Problema de Decisión s f a c i m t í r f o g l A f
s a c i n c é T e d
f f
f
s i s i l á f n A
FUNCIÓN OBJETIVO, que hay que minimizar o maximizar y …, xn. depende de las variables x1, …, x DOMINIO, que contiene el conjunto de valores que pueden tomar las variables. FUNCIÓN SOLUCIÓN, que permite saber si unos determinados valores de las variables son o no solución del problema. DECISIÓN, que es la asignación de un valor a una variable. RESTRICCIONES, que son las condiciones que deben cumplir las soluciones. FUNCIÓN FACTIBLE, que permite saber si una solución cumple o no las restricciones. SOLUCIÓN EN CURSO, que es el conjunto de decisiones factibles tomadas hasta el momento.
Metodología y Tecnología Tecnología de la Programación II
67
Espacio de Búsqueda s f La solución del problema puede expresarse como una tupla a c i ( x x1,…, x xn) con xi∈C i, siendo C i el dominio de xi. n m t í r f Así pues, el número total de posibles soluciones es k i o i =1 g l siendo k i el número de elementos de C i. A
∏
f
s a c i n c é T e d
El conjunto de todas las posibles soluciones se conoce como ESPACIO DE BÚSQUEDA y se representa como un árbol R x11 x21 x22 … x2k2
s i s i l á n A
x12
...
x21 x22 … x2k2
...
xn1 xn2 … xnkn
Metodología y Tecnología Tecnología de la Programación II
. ..
1ª decisión
x21 x22 … x2k2
2ª decisión
…
…
...
x1k 1
.. . xn1 xn2 … xnkn
nª decisión
e c o r r i d o e n p r o f u n d i d a d
68
Recorrido en Profundidad del Espacio de Búsqueda s f a c i m t í r o g f l A
s a c i n c é T e d
f
s i s i l á n A
Las soluciones se construyen partiendo de la raíz del espacio de búsqueda y tomando decisiones realizando un recorrido en profundidad del mismo. Se dice una solución en curso es COMPLETABLE si a partir de ella se puede alcanzar la solución del problema. Mientras que la técnica de fuerza bruta recorrería todo el espacio de búsqueda, lo que supondría un coste exponencial , la técnica de vuelta atrás, cuando llega a una solución no completable, da marcha atrás y busca por otro camino del espacio de búsqueda, evitando así recorrer todo el subárbol que queda por debajo de dicha solución no completable.
Metodología y Tecnología Tecnología de la Programación II
69
Diferentes Versiones de Algoritmos con Vuelta Vuelta Atrás s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Dependiendo del tipo de problema que tengamos que resolver existen diferentes formas de aplicar la vuelta atrás: – Vuelta atrás para una solución : El algoritmo recorre el espacio de búsqueda hasta que encuentra la primera solución. Es el más sencillo. – Vuelta atrás para todas las soluciones : El algoritmo recorre el espacio de búsqueda guardando todas las soluciones que encuentra hasta que ya no haya más. – Vuelta atrás para la mejor solución : El algoritmo recorre el espacio de búsqueda comparando cada solución que encuentra con la mejor solución obtenida hasta el momento, y quedándose con la mejor. Cuando ya no hay más soluciones, devuelve la mejor encontrada. Suele aplicarse a problemas de optimización.
Metodología y Tecnología Tecnología de la Programación II
70
Algorítmo Genérico con Vuelta Atrás para Todas Todas las Soluciones s f El siguiente algoritmo calcula todas las a c i problema con la técnica de vuelta atrás m t í r funcion funci on vue vuelta lta_at _atra ras(e s(ente ntero ro i,s i,sol ol[n] [n]) ) o g para_todo x en Ci l A
soluciones de un
sol[i]=x si comp completa letable( ble(sol, sol,i) i) ento entonces nces si so soluc lucion ion(s (sol) ol) entonc entonces es guardar(sol) fin_si si (i (i
s a c i n c é T e d
s i s i l á n A
Metodología y Tecnología Tecnología de la Programación II
71
Poda del Espacio de Búsqueda s f a c i m t í r o g f l A
s a c i n c é T e d
f
s i s i l f á n A
El algoritmo anterior no genera el espacio de búsqueda de forma explícita, sino implícitamente mediante llamadas recursivas. Cuando se llega a una solución en curso no completable, no se realizan más llamadas recursivas y por tanto no se construye el subárbol correspondiente del espacio de búsqueda. Esto se conoce como PODA del espacio de búsqueda. La poda es un mecanismo que permite descartar del recorrido ciertas zonas del espacio de búsqueda, bien porque allí no haya soluciones, bien porque ninguna de las soluciones de esas zonas es la óptima. Cuanto mayor sea el número de nodos podados, más eficiente será la búsqueda de soluciones.
Metodología y Tecnología Tecnología de la Programación II
72
Coste Temporal del Algoritmo de Vuelta Atrás s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
f
El coste temporal de un algoritmo que utilice la técnica de vuelta atrás, suele depender de: – El número de nodos del espacio de búsqueda que se visitan v(n). – El coste de las funciones solucion y completable en p((n). cada nodo p p(n)v(n)). En total O( p( Si se consigue que la función completable pode muchos nodos, el tamaño de v(n) se puede reducir drásticamente: – Si se reduce a un solo nodo (solución voraz) tendremos un coste O( p( p(n)n). – Por el contrario, en el peor de los casos (solución por p(n)k n). fuerza bruta), tendremos un coste O( p(
Metodología y Tecnología Tecnología de la Programación II
73
Ejemplos de Vuelta Atrás s f Algunos problemas conocidos que a c i mediante la técnica de vuelta atrás: m t í r – El problema de las ocho reinas. o g l – La suma de subconjuntos. A
s a c i n c é T e d
– – – –
pueden resolverse
El problema de la mochila entera. El problema del coloreado de grafos. La búsqueda de ciclos ciclos Hamiltonianos Hamiltonianos en grafos. El recorrido de un laberinto.
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
74
El Problema del Coloreado de Grafos s f a c i m t í r o g l A f
s a c i n c é T e d
f
Se dispone de un grafo G y de k colores. ¿Es posible colorear los vértices de G de manera que no haya dos vértices adyacentes con el mismo color? Otro famoso problema reducible a este es el del coloredado de mapas. ¿Puede pintarse un mapa de manera que no haya dos regiones adyacentes con el mismo color, utilizando k colores? Cada región se representa como un vértice del grafo y si dos regiones son adyacentes, sus respectivos vértices de conectan con una arista.
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
75
Coloreado de Grafos Espacio de Búsqueda s f a c i m t í r o g l A f s a c i n c é T e d
s i s i l á n A
Si el grafo tiene n vértices, representaremos el color de cada vértice en un vector color[ color[n n]={ ]={cc1,…, ,…,ccn} siendo, ci∈{1,…, {1,…,k k } el color del vértice i. El espacio de búsqueda asociado tiene k n posibles soluciones. Por ejemplo, para n=3 y k =3 =3 se tiene el siguiente espacio de búsqueda con 27 posibles soluciones.
1
1
1
2
2
2
3
1
2
3
3
1
2
1
3
1
Metodología y Tecnología Tecnología de la Programación II
2
2
3
1
2
1er vértice
3
3
3
1
2
1
3
1
2
2
3
1
2
2º vértice
3
3
1
2
3
3er vértice 76
Coloreado de Grafos Algoritmo con Vuelta Vuelta Atrás s f La siguiente función en C++ resuelve el problema del a c i coloreado de grafos con la técnica de vuelta atrás: m t í r void co void colo lore rea( a(in int t n, n,in int t k, k,bo bool ol ** **ad ady, y,in int t co colo lor[ r[], ],in int t i){ i){ o g for fo r (int (int j=0 j=0;j< ;j
s a c i n c é T e d
s i s i l á n A
color[i]=j; if (completable(ady,color,i)) if (i==n-1) imprimir(n,color); else colorea(n,k,ady,color,i+1);
} return; } bool completable completable(bool (bool **adj,int color[],i color[],int nt i){ int j=0; for (i (int nt j=0 =0;j ;j
Metodología y Tecnología Tecnología de la Programación II
77
Coloreado de Grafos Ejemplo s f Aplicando a c i m t í r o g l A
s a c i n c é T e d
la función anterior al mapa de 5 regiones
0 1 1 1 0 1 0 1 0 1 0 1 2 Ady = 1 1 0 1 1 3 4 1 0 1 0 1 0 1 1 1 0 con 3 colores 0, 1 y 2, se obtienen seis posibles soluciones
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
78
Algoritmo Genérico Genérico con Vuelta Atrás para la Mejor Me jor Solución Mejor s f El siguiente algoritmo calcula la mejor a c i problema de optimización con la técnica de m t í r funcion funci on vue vuelta lta_at _atra ras(e s(ente ntero ro i,s i,sol ol[n] [n]) ) o g para_todo x en Ci hacer l A
solución de un vuelta atrás
sol[i]=x si com compl pleta etable ble(so (sol,i l,i) ) cost coste(so e(sol,i) l,i)
s a c i n c é T e d
s i s i l á n A
Metodología y Tecnología Tecnología de la Programación II
79
Poda Basada en la Mejor Solución s f a c i m t í r o g f l A
s a c i n c é T e d
f
s f i s i l á n A
Cuando estemos ante un problema de optimización, el objetivo del algoritmo es recorrer el espacio de búsqueda para encontrar la mejor solución. En este caso, además de la poda que realiza la función completable, podemos realizar otra poda basada en el coste de la mejor solución en curso. La idea es que una solución en curso se poda, cuando, a pesar de ser completable, no es posible conseguir una solución mejor que la mejor solución en curso, aún cuando se genere genere todo todo el subárb subárbol ol del espac espacio io de búqued búqueda a que cuelga de ella (coste(sol,i) mejorcoste). Como antes, esta poda es más efectiva cuantos más nodos consiga eliminar.
Metodología y Tecnología Tecnología de la Programación II
80
El Problema de la Mochila Entera Espacio de Búsqueda s f a c i m t í r f o g l A
s a c i n c é T e d
El problema de la mochila entera también puede resolverse mediante la técnica de vuelta atrás. Si tenemos n objetos y representamos el contenido de la mochila con un vector sol[ sol[n n]={ x1,…, x xn} donde 0 si el objeto i no está en la mochila xi = 1 si el objeto i está en la mochila entonces el espacio de búsqueda asociado es 0 0
s i s i l á n A
1 0
1
Objeto 1 1
Objeto 2
…
... 0
1
. ..
.. . 0
1
Objeto n
Metodología y Tecnología Tecnología de la Programación II
81
El Problema de la Mochila Entera Poda Basada en la Mejor Solución s f a c i m t í r o g l f A
s a c i n c é T e d
f
s i s i l á f n A
Puesto que se trata de un problema de optimización, aplicaremos también la poda basada en la mejor solución en curso. cota(sol,ii) que Para ello resulta útil disponer de una función cota(sol, calcule una cota superior del valor de la mochila en las soluciones que pueden obtenerse a partir de la solución en curso. Con esta función, cada vez que cota(sol, cota(sol,ii) < maxval, siendo maxval el máximo valor de la mochila encontrado hasta el momento (al comienzo maxval=0), podaremos el subárbol del espacio de búsqueda que cuelgue de dicha solución en curso y haremos la vuelta atrás. En nuestro caso, esta cota puede obtenerse mediante el algoritmo voraz para el problema de la mochila fraccionada.
Metodología y Tecnología Tecnología de la Programación II
82
El Problema de la Mochila Entera Algoritmo con Vuelta Vuelta Atrás s f La siguiente función en C++ resuelve el problema a c i mochila entera con la técnica de vuelta atrás: m t í r void lle void llenar nar(in (int t sol sol[], [],flo float at valact valact,fl ,float oat pes pesoac oact, t, o g int in t me mejo jors rsol ol[] [],f ,flo loat at &m &max axva val, l,in int t i) i){ { l A
de la
float tval,tpeso; for fo r (int j=1 j=1;j> ;j>=0 =0;j;j--){ -){ sol[i]=j; tval=valact+j*valor[i]; tpeso=pesoact-j*peso[i]; if (tpeso>=0 && maxval
s a c i n c é T e d
s i s i l á n A
}
Metodología y Tecnología Tecnología de la Programación II
83
El Problema de la Mochila Entera Función Cota del Valor Máximo s f Siendo n (número de objetos) valor[] (valor de los a c i objetos) y peso[] (peso de los objetos) variables globales, y m t í siendo la función cotaval la siguiente: r o g l float floa t cota cotava val( l(fl floa oat t va val, l,fl floa oat t pe peso soma max, x,in int t i) i){ { A
for (int for (int j=i j=i;j< ;j
s a c i n c é T e d
}
Para que esta función trabaje correctamente, es necesario que los objetos estén ordenados de manera decreciente por valor/peso. f Además, no es necesario que los pesos sean enteros como ocurría con la programación dinámica. f
s i s i l á n A
Metodología y Tecnología Tecnología de la Programación II
84
El Problema de la Mochila Entera Ejemplo s f a c i m t í r o g l A
s a c i n c é T e d
1 0
1
0 0
1
1
1 0
Objeto 0 p=6,v=30
0
1
1 s i s i l á n A
Si hay 5 objetos de valores valor[]={30,40,60,10,20} y pesos peso[]={6,10, peso[]={6,10,20,5,15} 20,5,15}, entonces la función realiza el siguiente recorrido del espacio de búsqueda
1
0 0
1
0
1 0
1
0 0
Objeto 1 p=10,v=40
1
1 0
1
Objeto 2 p=20,v=60
0 0
1
0
Objeto 3 p=5,v=10
Objeto 4 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 p=15,v=20 maxval
80
90
100
Metodología y Tecnología Tecnología de la Programación II
85
Mejoras de la Vuelta Atrás Una posible mejora sería comenzar buscando una solución factible por algún procedimiento rápido, e inicializar el valor de la mejor solución con el valor de dicha solución. De esta manera, la poda basada en mejor solución comenzaría a funcionar antes. posible mejora mejora consiste consiste en guardar para cada varia variable ble f Otra posible s a xi la lista de los valores de su dominio C i : c i n – Cada vez que se asigna un valor a una variable, se c é T eliminan de todas las variables no asignadas los valores e d incompatibles con la asignación. Esto reduce el espacio de búsqueda aunque también supone un coste. s – Si a alguna variable no le quedan valores posibles, i s i l entonces no es posible la solución y se hace vuelta atrás. á n A f También está la posibilidad de considerar árboles con recorrido dinámico para los espacios de búsqueda. Metodología y Tecnología Tecnología de la Programación II 86 s f a c i m t í r o g l A
Ramificación y Poda (Bra (B ranc nch h & Boun Bound) d) s f a c i m t í r o g f l A
s a c i n c é T e d
f
s i s i l á n A f
La técnica técnica de RAMIFICACIÓN RAMIFICACIÓN Y PODA es básicamente una mejora de la técnica de vuelta atrás que se basa en un recorrido dinámico más eficiente del espacio de búsqueda. La principal diferencia es que, mientras que la técnica de vuelta atrás realiza un recorrido ciego del espacio de búsqueda, la técnica de ramificación y poda realiza un recorrido informado. En un recorrido ciego, bien sea en profundidad o en anchura, se conoce perfectamente el siguiente nodo a visitar (siguiente hijo o hermano del nodo actual), es decir, el orden del recorrido está establecido a priori, mientras que en un recorrido informado, se busca el siguiente nodo más prometedor en base a la información de que se disponga. Se aplica fundamentalmente a problemas de optimización con restricciones, donde el espacio de búsqueda es un árbol. árbo l.
Metodología y Tecnología Tecnología de la Programación II
87
Nodos Prometedores Prometedores s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
f
f
Diremos que un nodo del espacio de búsqueda es PROMETEDOR, si la información que tenemos de ese nodo en el recorrido indica que expandiéndolo se puede conseguir una solución mejor que la mejor solución obtenida hasta el momento. Esta información puede provenir de la evaluación del camino ya recorrido hasta el nodo, o bien de la evaluación de los caminos quedan por recorrer desde el nodo a posibles soluciones. Para guiar la búsqueda es fundamental disponer de una función que, no sólo diga si un nodo es o no prometedor, sino que además estime lo prometedor que es.
Metodología y Tecnología Tecnología de la Programación II
88
Caracterización del Espacio de Caracterización Búsqueda en Ramificación y Poda s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á f n A
El espacio de búsqueda se representa mediante un árbol en el que hay tres clases de nodos: – Nodo vivo: Es un nodo hasta el cual la solución en curso es factible, prometedora, y del que no se han generado aún todos sus hijos (no se ha completado la solución). Indican caminos abiertos de búsqueda. – Nodo muerto: Es un nodo del que no van a generarse más hijos porque, o bien ya se han generado todos sus hijos, o bien no es factible, o bien no es prometedor. Indican caminos cerrados de búsqueda. – Nodo en expansión: Es aquel del que se están generando sus hijos en un determinado instante. En un determinado instante de la búsqueda puede haber muchos nodos vivos y muertos pero sólo uno en expansión.
Metodología y Tecnología Tecnología de la Programación II
89
Funcionamiento de la Búsqueda en Ramificación y Poda s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
f
En la técnica de vuelta atrás, cada vez que se generaba un hijo del nodo en expansión, este pasaba inmediatamente a ser el nodo en expansión. En consecuencia, los únicos nodos vivos son los que están en el camino de la raíz al nodo en expansión. Por el contrario, en la técnica de ramificación y poda se generan todos los hijos del nodo en expansión antes de que cualquier otro nodo vivo pase a ser el nuevo nodo en expansión. Esto supone que puede haber nodos vivos en distintos caminos y tendremos que guardar la lista de nodos vivos en alguna estructura de datos (suelen ser pilas o colas).
Metodología y Tecnología Tecnología de la Programación II
90
Estrategias de Búsqueda s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Existen diferentes estrategias para elegir el siguiente nodo en expansión de la lista de nodos vivos: – Más antiguo. Se elige como nodo en expansión el más antiguo de la lista. En este caso la lista se implementa como co mo una una col cola. a. Pr Prod oduc uce e un rec recor orri rido do en en anch anchur ura. a. – Menos antiguo. Se elige como nodo en expansión el menos antiguo de la lista. En este caso la lista se implementa como una pila. Produce un recorrido en profundidad. – Más prometedor . Se elige como nodo de expansión el nodo más prometedor de la lista. La lista se implementa como una cola con prioridades, donde la prioridad de un nodo es lo prometedor que es. Produce un recorrido informado y ¡es el que suele utilizar la técnica de ramificación y poda!
Metodología y Tecnología Tecnología de la Programación II
91
Algoritmo Genérico Genér ico con Genérico Ramificación y Poda s f El siguiente algoritmo calcula la mejor solución de un a c i problema de optimización con ramificación y poda: m t í r funcion rami funcion ramifica ficacion cion_y_p _y_poda( oda() ) o g inicializar(C); insertar(C,
s a c i n c é T e d
s i s i l á n A
mientras no_vacia(C) hacer
Metodología y Tecnología Tecnología de la Programación II
92
Algoritmo Genérico Genér ico con Genérico Ramificación y Poda s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l f á n A
En el algoritmo anterior se tiene que: – C es una cola con prioridades, es decir, sus elementos están ordenados de acuerdo a sus prioridades. – prioridad(sol prioridad(sol,k) ,k) es una función que devuelve la prioridad de un nodo vivo, que será lo prometedor que es. Esta función sirve para dirigir la búsqueda y llegar pronto a la solución óptima. – La condición completable(sol,k) sirve para realizar una poda cuando la solución no es factible, mientras que la condición coste(sol,k)
Metodología y Tecnología Tecnología de la Programación II
93
Ramificación y Poda Coste Temporal s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
El coste temporal de un algoritmo que utilice la técnica de ramificación y poda, depende fundamentalmente de: – El número de nodos del espacio de búsqueda que se visitan v(n). Que depende a su vez de lo buenas que sean las funciones completable y coste para hacer podas, y lo buena que sea la función prioridad para dirigir la búsqueda. – El coste de las funciones prioridad , completable y p((n). coste en cada nodo p – El coste del mantenimiento de la cola con prioridad. p(n)v(n)), donde v(n) suele ser d n con d = max |C k |. En total O( p(
Metodología y Tecnología Tecnología de la Programación II
94
El Problema de la Mochila Entera Mejora con Ramificación y Poda s f a c i m t í r o g l A f
s a c i n c é T e d
Se puede mejorar la solución dada al problema de la mochila entera con la técnica de vuelta atrás, si, además de las podas que realizaba esta, se dirige la búsqueda con la función de prioridad. Tomando como función de prioridad la misma función que la que calculaba una cota superior del valor de la mochila para cada nodo del espacio de búsqueda, se expandirán primero los nodos que tengan una cota mayor, y que probablemente llevarán a una solución con un valor de la mochila mayor.
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
95
El Problema de la Mochila Entera Estructura de un Nodo s f a c i m t í r o g f l A
Cada nodo del espacio de búsqueda debe contener la información necesaria para generar sus hijos o para decidir si es solución o no puede serlo. Utilizaremos la siguiente estructura de datos en C++:
s a c i n c é T e d
class nodo{ private: int num numel; el; int *sol *sol; ; int ac act tual al; ; float floa t pes; float floa t val; float floa t prio; prio; }
s i s i l á n A
// // // // // // //
Número tot Número total al de ob objet jetos os Vector Vect or solu solución ción Obje Obj eto has ast ta el que se ha han toma mad do deci cis sion ones es Peso rest restante ante de la moch mochila ila Valor Valo r de la moch mochila ila Prioridad Prior idad del nodo nodo
Los valores de pes y val podrían calcularse sin necesidad de almacenarlos pero es más eficiente pasarlos a los hijos. Esto se conoce como MARCAJE.
Metodología y Tecnología Tecnología de la Programación II
96
El Problema de la Mochila Entera Función de Coste y Prioridad s f La siguiente función en C++ se utiliza como función de coste a c i parar la poda y también como función de prioridad para m t í dirigir la búsqueda r o g l float cota float cotavalo valor(no r(nodo do *x){ A nod no do *si sig g; int i=x i=x->e ->eta tapa( pa(); ); s if (i>=x->numobjetos() || x->peso()==0) return x->valor(); a c else if (weight[i]>x->peso()) i n c return x->valor()+x->peso()/weight[i]*value[i]; é T else { e sig=new nodo(*x); d sig->suma_valor(value[i]); sig->resta_peso(weight[i]); s i sig->sig_etapa(); s i l return val_bound(sig); á n } A Metodología y Tecnología Tecnología de la Programación II
97
El Problema de la Mochila Entera Algoritmo con Ramificación Ramificación y Poda Poda s f La siguiente función en C++ resuelve el problema a c i mochila entera con la técnica de ramificación y poda: m t í nodo* rellenar(i nodo* rellenar(int nt n,fl n,float oat pesomax) pesomax){ { r o priority_queue
de la
98
El Problema de la Mochila Entera Algoritmo con Ramificación Ramificación y Poda Poda hijo->fija_prio(cotaval(hijo)); if (hijo->peso()>=0 && solucion->valor()
s a c i m t í r o g l A
s a c i n c é T e d
} delete nodoexp; } return solucion; } f
s i s i l á f n A
Siendo c una cola con prioridad implementada en la librería de plantillas estándar de C++, con el orden bool mayor_pri::op mayor_pri::operator()(nodo erator()(nodo *a,nodo *b){ return (a->prioridad()
Y siendo valor[] (valor de los objetos) y peso[] (peso de los objetos) variables globales.
Metodología y Tecnología Tecnología de la Programación II
99
El Problema de la Mochila Entera Ejemplo s f a c i m t í r o g l A
Si hay 5 objetos de valores valor[]={30,40,60,10,20} y pesos peso[]={6,10, peso[]={6,10,20,5,15} 20,5,15}, entonces la función realiza el siguiente recorrido del espacio de búsqueda c=112
1
c=112 s a c i n c=118 c é T 1 e d
1 s i s i l á n A
c=100
c=98
1
0
1
1
0 0
1
c=70
1
0
c=103
c=100
0
0
1
Objeto 1 p=10,v=40
0
c=100
1 0
c=76,67
1
c=92
0
0
c=100
0
Objeto 0 p=6,v=30
1
1 0
1
Objeto 2 p=20,v=60
0 0
1
0
Objeto 3 p=5,v=10
120 100
Objeto 4 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 p=15,v=20 maxval 100
Metodología y Tecnología Tecnología de la Programación II
100
El Problema del Viajante s f a c i m t í r o g l f A
Recordemos que se trata de buscar el camino más corto para visitar n ciudades y volver a la ciudad de partida sin pasar dos veces por la misma ciudad. Ya vimos una solución con programación dinámica, pero requería un coste en memoria excesivo.
s a c i n c é T e d
%
6
3
4 2
s i s i l á n A
3
2 2
%
5 3
4 6
Metodología y Tecnología Tecnología de la Programación II
%0
?
%
5
1
101
El Problema del Viajante Modelizac Mode lización ión Medi Mediante ante Graf Grafos os Modeliza Modelización ción s f a c i m t í r o g l A
s a c i n c é T e d
s i s f i l á n A
Como ya vimos vimos,, modelizaremo modelizaremoss el problema problema con un un grafo G=( =(V,A V,A)) donde – V ={1,…,n ={1,…,n} es el conjunto de vértices (ciudades). – A es el conjunto de aristas (i j) ,j) con i j ,j ∈ V (caminos). – D(i j) , j) es la longitud de (i j) ,j) si (i j) ,j) ∈ A, o ∞ si (i j) ,j) ∉ A. De\A 0 1 2 3 0 ∞ 3 ∞ 3 1 5 ∞ 4 ∞ 2 2 6 ∞ 6 3 2 5 4 ∞
Representaremos la solución con un vector sol[n sol[n] que almacenará en la posición i, la ciudad a visitar en i-esimo lugar.
Metodología y Tecnología Tecnología de la Programación II
102
El Problema del Viajante Espacio de Búsqueda s f a c i m t í r o g l A f
s a c i n c é T e d
El conjunto de posibles soluciones serán todas las permutaciones de las n-1 ciudades que hay que visitar, es decir (n-1)! Si por ejemplo, tenemos 4 ciudades, el árbol del espacio de búsqueda tendrá 3!= 6 ramas, que serán 0 Origen 1
s i s i l á n A
2
3
1ª visita
2
3
1
3
1
2
2ª visita
3
2
3
1
2
1
3ª visita
0
0
0
0
0
0
Destino
R e c o r r i d o
Metodología y Tecnología Tecnología de la Programación II
103
Determinación de una Cota del Coste para una Solución en Curso s f a c i m t í r o g f l A
s a c i n c é T e d
f
Para que la poda basada en la mejor solución sea efectiva, conviene utilizar un buena función que acote inferiormente el coste del camino mínimo para una solución en curso. Una cota muy sencilla podría ser la suma de los caminos ya elegidos. Parece lógico también utilizar esta cota como prioridad, ya que, en principio, los caminos más cortos recorridos hasta el momento, parecen los más prometedores y deben intentarse en primer lugar.
s i s i l á n A Metodología y Tecnología Tecnología de la Programación II
104
El Problema del Viajante Algoritmo con Ramificación Ramificación y Poda Poda s f La siguiente función en C++ resuelve el problema a c i viajante con al técnica de ramificación y poda: m t í r nodo* cami nodo* camino_m no_minim inimo(in o(int t n){ o g priority_queue
s a c i n c é T e d
s i s i l á n A
del
nodo ra nodo raiz iz(n (n); ); raiz.sig_etapa(); c.push(&raiz); nodo nod o *hij *hijo,*n o,*nodoe odoexp,* xp,*sol; sol; sol=new nodo(n); sol->fija_distancia(DMAX); while (!c.empty()){ (!c.empty()){ nodoexp=c.top(); c.pop();
Metodología y Tecnología Tecnología de la Programación II
105
El Problema del Viajante Algoritmo con Ramificación Ramificación y Poda Poda s a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
if (nodoexp->distance()
Metodología y Tecnología Tecnología de la Programación II
106
El Problema del Viajante Algoritmo con Ramificación Ramificación y Poda Poda s f Siendo la interfaz de la clase nodo la siguiente a c i class no cla nodo do{ { m t í int nume numel; l; // Núme Número ro de ciud ciudades ades r o int *camino; // Ciudades visitadas hasta el momento g l A int actu actual; al; // Etap Etapa a actu actual al del viaj viaje e s a c i n c é T e d
s i s i l á n A
float dist; // Distancia recorrida hasta el momento public: nodo(int nod o(int n); // Cons Constru tructor ctor por defe defecto cto nodo(con nod o(const st nodo &a); // Cons Construc tructor tor de copi copia. a. void vo id vis visit ita(i a(int nt x); // Vis Vista ta la ciu ciuda dad d x void voi d sig_ sig_etap etapa(); a(); // Pasa a la sigu siguient iente e etap etapa a void vo id fij fija_ a_dis distan tancia cia(fl (floa oat t a); // Fij Fija a la dis distan tancia cia float distancia( distancia(); ); // // Devuelve Devuelve la distancia distancia recorrida bool visitado( visitado(int int x); //Comprueba //Comprueba si se se ha visitado visitado x bool solucion( solucion(); ); // Mira si ha terminado terminado el viaje viaje };
Metodología y Tecnología Tecnología de la Programación II
107
El Problema del Viajante Ejemplo con Ramificación y Poda s f a c i m t í r o g l A
s a c i n c é T e d
Para nuestro ejemplo, esta función realizaría el siguiente recorrido del espacio de búsqueda: 0
3 7
2
1
3
∞
2
∞
3
1
8
3
13
3
2
3
0
15
Metodología y Tecnología Tecnología de la Programación II
0
7
2ª visita
1
3ª visita
0
0
Destino
14 Min
18
1 0
1ª visita 2
13
2 14
0
3
1 12
15 s i s i l á n A
Origen R e c o r r i d o
18
Distancia 108
El Problema del Viajante Mejora de la Poda s f a c i m t í r o g f l A
s a c i n c é T e d
f
s f i s i l á n A
Se puede conseguir una poda más efectiva del espacio de búsqueda si se calcula la cota inferior del coste del camino mínimo reduciendo la matriz de adyacencia. Una matriz reducida es una matriz cuyos elementos son no negativos y además, cada fila y cada columna contiene al menos un 0. Se puede reducir una matriz restando cantidades constantes a los elementos de sus filas o columnas. En tal caso, si se resta la misma constante c a todos los elementos de una fila o columna de la matriz de adyacencia, cualquier circuito hamiltonia hamil toniano no se verá reducido reducido en dicha cantidad cantidad c. En consecuencia, se puede utilizar la suma de constantes utilizadas en la reducción de la matriz de adyacencia como cota inferior de la distancia mínima.
Metodología y Tecnología Tecnología de la Programación II
109
Reducción de la Matriz de Adyacencia (Ejemplo) s f a c i m t í r o g l A
s a c i n c é T e d
f
s i s i l á f n A
Consideremos la matriz de adyacencia del ejemplo: ∞ 3 ∞ 3 5 ∞ 4 ∞ ∞ 2 6 6 2 5 4 ∞ Para reducir la primera fila, tomamos como c el mínimo elemento de dicha fila y lo restamos a toda la fila ∞ 3 ∞ 3 ∞ 0 ∞ 0 5 ∞ 4 ∞ 5 ∞ 4 ∞ Fila 1 c=3 2 6 ∞ 6 2 6 ∞ 6 2 5 4 ∞ 2 5 4 ∞ Y la cota inferior del camino mínimo es 3.
Metodología y Tecnología Tecnología de la Programación II
110
Reducción de la Matriz de Adyacencia (Ejemplo) s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Continuando con la reducción queda
∞ 0 ∞ 0 ∞ 0 ∞ 0 ∞ 0 ∞ 0 5 ∞ 4 ∞ 1 ∞ 0 ∞ 1 ∞ 0 ∞ Fila 2 c=4 Fila 3 c=2 ∞ ∞ ∞ 2 6 6 2 6 6 0 4 4 2 5 4 ∞ 2 5 4 ∞ 2 5 4 ∞ ∞ 0 ∞ 0 ∞ 0 ∞ 0 1 ∞ 0 ∞ 1 ∞ 0 ∞ ¡Matriz Fila 4 c=2 0 4 ∞ 4 0 4 ∞ 4 Reducida! 2 5 4 ∞ 0 3 2 ∞ f Y la suma total de las constantes restadas es 3+4+2+2=11, que es una cota inferior del camino mínimo. f Utilizando esta cota como la prioridad de cada nodo, la poda es mucho mayor y el algoritmo más eficiente.
Metodología y Tecnología Tecnología de la Programación II
111
Cálculo de la Cota Inferior para los Nodos del Espacio de Búsqueda s f a c i m t í r f o g l A
s a c i n c é T e d
s i s i l á n A
Veamos cómo calcular la cota inferior para los nodos distintos del raíz. Supongamos que A es la matriz de adyacencia reducida para un nodo x, y sea y el nodo hijo de x que se obtiene al ,j) en el recorrido. Entonces para calcular la incluir la arista (i j) cota inferior del nodo y, hay que seguir los pasos siguientes: – Cambiar todos los elementos de la fila i y la columna j de A por ∞. – Reducir la matriz A con excepción de la fija i y columna j. A((i j) ,j) – La cota del nodo y es la suma de la cota del nodo x, A A. y las constantes restadas al reducir A
Metodología y Tecnología Tecnología de la Programación II
112
Cálculo de la Cota Inferior Ejemplo s f a c i m t í r o g l A
s a c i n c é T e d
s i s i l á n A
Siguiendo con el ejemplo: ∞ 0 ∞ 1 ∞ 0 0 4 ∞ 0 3 2 0 1 ∞ ∞ ∞ 0 ∞ ∞ ∞ 2
∞ 1 0 0
∞ ∞ 0 ∞
Cota=11+0+4
∞ 0 0 0
0
∞ Cota=11 4 ∞
2 ∞ ∞ ∞ ∞ 1 ∞ 0 ∞
3 ∞ ∞ ∞ ∞ 1 ∞ 0 ∞ 0 1 ∞ ∞ 0 0 2 ∞
∞ ∞ 0 ∞ Cota=11+∞+8
Cota=11+0+3
Metodología y Tecnología Tecnología de la Programación II
113
El Problema del Viajante Ejemplo con Mejora de la Poda s f a c i m t í r o g l A
Para nuestro ejemplo, con esta otra cota se realizaría el siguiente recorrido el espacio de búsqueda: 0
15
2
2 3
1
Origen
14
∞
1 s a c i n c é T e d
11
14
3
3
18
1ª visita
1
2
2ª visita
2
1
3ª visita
0
0
Destino
14
3
2
3
1
R e c o r r i d o
14 s i s i l á n A
0
0
Metodología y Tecnología Tecnología de la Programación II
0
0
14 Min
Distancia 114