Algorítmica y Complejidad Tema 5 – Divide y Vencerás. Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 2 Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 3 Método. ¡Esquema de tres etapas! Dividir. El problema se divide en varios problemas similares de menor tamaño. Resolver. Si los subproblemas son asumibles se resuelven. En caso contrario se vuelve a aplicar el método. Combinar. Se combinan las soluciones de los subproblemas para obtener la solución total. Divide y vencerás. 4 Método. Características que deben cumplir los problemas para que se pueda aplicar esta técnica: El problema se debe poder descomponer en otros similares pero más pequeños. Los nuevos problemas deben ser disjuntos. Debe ser posible combinar las individuales para obtener la global. Divide y vencerás. soluciones 5 Método. procedure Divide_y_Vencerás (P : problema) is begin if P es simple then Solucionar P; else Descomponer P en {P1, P2, ..., Pn}; Divide_y_Vencerás (P1); Divide_y_Vencerás (P2); ................... Divide_y_Vencerás (Pn); Combinar las soluciones de {P1, P2, ..., Pn}; end if; end Divide_y_Vencerás; Divide y vencerás. 6 Método. ¿Hasta donde conviene subdividir el problema? T (n) Algoritmo Inmediato Existirá un umbral n0 por debajo del cuál será más rápido aplicar el algoritmo inmediato. Algoritmo Div. y Venc. n0 n El cálculo de n0 no es trivial y depende de la implementación. Es habitual utilizar métodos empíricos para su determinación. Divide y vencerás. 7 Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 8 Un ejemplo sencillo. Problema: “Encontrar el valor máximo en un array de números enteros." A: 1 2 3 4 -23 14 31 -3 .... n-1 n 13 -2 La solución inmediata sería: function Maximo (i, j : integer) return integer is max : integer := integer'first; begin for k in i .. j loop if A(k) > max then max := A(k); end if; end loop; return max; end Maximo; ___________________________ put ("Valor maximo:"); put (Maximo(A'first, A'last)); Divide y vencerás. 9 Un ejemplo sencillo. Enfoque "divide y vencerás": 1. Dividir el array en dos partes. 2. Hallar el máximo de cada parte. 3. Seleccionar el mayor de los dos. Se sigue aplicando de forma recursiva. Divide y vencerás. 10 Un ejemplo sencillo. function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin end Maximo; ___________________________ put ("Valor maximo:"); put (Maximo(A'first, A'last)); Divide y vencerás. 11 Un ejemplo sencillo. function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin if i=j then return A(i); else end if; end Maximo; ___________________________ put ("Valor maximo:"); put (Maximo(A'first, A'last)); Divide y vencerás. 12 Un ejemplo sencillo. function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin if i=j then return A(i); else med := (i + j) / 2; max_i := Maximo (i, med); max_d := Maximo (med+1, j); end if; end Maximo; ___________________________ put ("Valor maximo:"); put (Maximo(A'first, A'last)); Divide y vencerás. 13 Un ejemplo sencillo. function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin if i=j then return A(i); else med := (i + j) / 2; max_i := Maximo (i, med); max_d := Maximo (med+1, j); if max_i > max_d then return max_i; else return max_d; end if; end if; end Maximo; ___________________________ put ("Valor maximo:"); put (Maximo(A'first, A'last)); Divide y vencerás. 14 Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 15 Complejidad del método. Problema 2 Problema Problema a-1 Problema 1 Problema 3 ... Problema a T(n/b) + T(n/b ) + T(n/b) + . . . + T(n/b) + T(n/b) T(n) aT(n/b) Descomposición del problema y combinación de las soluciones Divide y vencerás. O ( n k) 16 Complejidad del método. En general responderá a esta ecuación: T(n)=aT(n/b)+O(nk) : Número de subproblemas en que se descompone. a n/b : Tamaño de cada nuevo subproblema. a ≥ 1, b ≥ 2, k ≥ 0 Cuya solución es: O ( n k ), T(n)= a < bk O ( n k log n ), a = b k O ( n logb a ), a > bk ¡Teorema maestro! Divide y vencerás. 17 Complejidad del método. Complejidad del ejemplo sencillo: (Enfoque Divide y Vencerás) function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin if i=j then return A(i); else med := (i + j) / 2; max_i := Maximo (i, med); max_d := Maximo (med+1, j); if max_i > max_d then return max_i; else return max_d; end if; end if; end Maximo; Divide y vencerás. O(1) O(1) 18 Complejidad del método. Complejidad del ejemplo sencillo: (Enfoque Divide y Vencerás) function Maximo (i, j : integer) return integer is med, max_i, max_d : integer; begin if i=j then return A(i); else med := (i + j) / 2; max_i := Maximo (i, med); max_d := Maximo (med+1, j); if max_i > max_d then return max_i; else return max_d; end if; end if; end Maximo; Divide y vencerás. T(n/2) T(n/2) 19 Complejidad del método. Complejidad del ejemplo sencillo: (Enfoque Divide y Vencerás) T(n)=aT(n/b)+O(nk) a=2 b=2 k=0 T(n)=2T(n/2)+O(1) a > bk 2 > 20 2 > 1 Divide y vencerás. O ( n logb a ) = O ( n log2 2 ) = O ( n ) 20 Complejidad del método. Complejidad del ejemplo sencillo: (Enfoque Inmediato) function Maximo (i, j : integer) return integer is max : integer := integer'first; begin for k in i .. j loop if A(k) > max then O max := A(k); end if; end loop; return max; end Maximo; (n) • Ambos métodos tienen la misma complejidad. • Divide y Vencerás es más lento por la recursividad. • En este caso es mejor el Enfoque Inmediato. Divide y vencerás. 21 Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 22 Ejemplo: El máximo subarray. Problema: "Dados varios números que supondremos almacenados en un array, se trata de encontrar la secuencia de números contiguos cuya suma sea máxima." Por ejemplo, dado: A: 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 6 7 8 8 12 5 La solución sería: cuya suma es 25. Si existe más de una solución, nos conformaremos con hallar una de ellas. Divide y vencerás. 23 Ejemplo: El máximo subarray. Una solución inmediata: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 Divide y vencerás. 24 Ejemplo: El máximo subarray. procedure Maximo_Subarray is .............. begin max := integer'first; for i in A'range loop suma := 0; for j in i .. A'last loop suma := suma + A(j); if suma > max then max := suma; inf := i; sup := j; end if; end loop; end loop; put ("Indice inferior: "); put (inf); put ("Indice superior: "); put (sup); put ("Valor de la suma : "); put (max); end Maximo_Subarray; Divide y vencerás. O ( n2 ) new_line; new_line; new_line; 25 Ejemplo: El máximo subarray. Enfoque "divide y vencerás": Se divide el array en dos partes. 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 Pueden darse tres casos: 1 2 3 4 5 6 7 8 9 10 El subarray está totalmente en la parte izquierda. 1 8 El subarray está totalmente en la parte derecha. 2 3 4 5 6 7 8 El subarray atraviesa la división. Divide y vencerás. 7 9 10 9 10 Ejemplo: El máximo subarray. Si el subarray está completamente en uno de los lados, se puede resolver de forma recursiva, finalizando cuando el tamaño sea de un sólo elemento. En el otro caso, el subarray tendrá una parte en el lado izquierdo y otra en el derecho. Las partes se corresponderán con uno de estos casos: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 12 2 -3 -4 -9 8 12 5 -6 1 12 2 -3 -4 -9 8 12 5 -6 1 El máximo subarray estará formado por la unión del de mayor suma en el lado izquierdo y el de mayor suma del lado derecho. Divide y vencerás. Ejemplo: El máximo subarray. procedure Maximo_Subarray (E_inf, E_sup : in natural; S_inf, S_sup : out natural; S_suma : out integer) is ........................................ begin end Maximo_Subarray; ___________________________ Maximo_Subarray (A'first, A'last, inf, sup, max); Divide y vencerás. Ejemplo: El máximo subarray. procedure Maximo_Subarray (E_inf, E_sup : in natural; S_inf, S_sup : out natural; S_suma : out integer) is ........................................ begin if E_inf = E_sup then S_suma := A(E_inf); else S_inf := E_inf; end if; end Maximo_Subarray; ___________________________ Maximo_Subarray (A'first, A'last, inf, sup, max); Divide y vencerás. S_sup := S_inf; O(1) Ejemplo: El máximo subarray. procedure Maximo_Subarray (E_inf, E_sup : in natural; S_inf, S_sup : out natural; S_suma : out integer) is ........................................ begin if E_inf = E_sup then S_suma := A(E_inf); else S_inf := E_inf; S_sup := S_inf; med := (E_inf + E_sup) / 2; Maximo_Subarray (E_inf, med, inf_i, sup_i, max_i); Maximo_Subarray (med + 1, E_sup,inf_d, sup_d, max_d); Subarray_Comun (E_inf, med, E_sup, inf_c, sup_c, max_c); end if; end Maximo_Subarray; ___________________________ Maximo_Subarray (A'first, A'last, inf, sup, max); Divide y vencerás. O(1) O(1) T(n/2) T(n/2) ? Ejemplo: El máximo subarray. procedure Maximo_Subarray (E_inf, E_sup : in natural; S_inf, S_sup : out natural; S_suma : out integer) is ........................................ begin if E_inf = E_sup then S_suma := A(E_inf); else S_inf := E_inf; S_sup := S_inf; med := (E_inf + E_sup) / 2; Maximo_Subarray (E_inf, med, inf_i, sup_i, max_i); Maximo_Subarray (med + 1, E_sup,inf_d, sup_d, max_d); Subarray_Comun (E_inf, med, E_sup, inf_c, sup_c, max_c); if max_i > max_d and max_i > max_c then S_suma := max_i; S_inf := inf_i; S_sup := sup_i; elsif max_d > max_i and max_d > max_c then S_suma := max_d; S_inf := inf_d; S_sup := sup_d; else S_suma := max_c; S_inf := inf_c; S_sup := sup_c; end if; end if; end Maximo_Subarray; ___________________________ Maximo_Subarray (A'first, A'last, inf, sup, max); Divide y vencerás. O(1) O(1) T(n/2) T(n/2) ? O(1) Ejemplo: El máximo subarray. procedure Subarray_Comun (E_inf, med, E_sup S_inf, S_sup S_suma ........................................ begin end Subarray_Comun; Divide y vencerás. : in natural; : out natural; : out integer) is Ejemplo: El máximo subarray. procedure Subarray_Comun (E_inf, med, E_sup S_inf, S_sup S_suma ........................................ : in natural; : out natural; : out integer) is begin suma_izq := integer'first; suma_tmp := 0; for i in reverse E_inf .. med loop suma_tmp := suma_tmp + A(i); if suma_tmp > suma_izq then suma_izq := suma_tmp; S_inf := i; end if; end loop; end Subarray_Comun; Divide y vencerás. O(n) Ejemplo: El máximo subarray. procedure Subarray_Comun (E_inf, med, E_sup S_inf, S_sup S_suma ........................................ : in natural; : out natural; : out integer) is begin suma_izq := integer'first; suma_tmp := 0; for i in reverse E_inf .. med loop suma_tmp := suma_tmp + A(i); if suma_tmp > suma_izq then suma_izq := suma_tmp; S_inf := i; end if; end loop; O(n) suma_der := integer'first; suma_tmp := 0; for i in med+1 .. E_sup loop suma_tmp := suma_tmp + A(i); if suma_tmp > suma_der then suma_der := suma_tmp; S_sup := i; end if; end loop; O(n) end Subarray_Comun; Divide y vencerás. Ejemplo: El máximo subarray. procedure Subarray_Comun (E_inf, med, E_sup S_inf, S_sup S_suma ........................................ : in natural; : out natural; : out integer) is begin suma_izq := integer'first; suma_tmp := 0; for i in reverse E_inf .. med loop suma_tmp := suma_tmp + A(i); if suma_tmp > suma_izq then suma_izq := suma_tmp; S_inf := i; end if; end loop; O(n) suma_der := integer'first; suma_tmp := 0; for i in med+1 .. E_sup loop suma_tmp := suma_tmp + A(i); if suma_tmp > suma_der then suma_der := suma_tmp; S_sup := i; end if; end loop; O(n) S_suma := suma_izq + suma_der; end Subarray_Comun; Divide y vencerás. O(1) Ejemplo: El máximo subarray. Complejidad del enfoque Divide y Vencerás: T ( n ) = O (1) + O (1) + T (n / 2) + T (n / 2) + O ( ? ) + O (1) O (n) + O (n) + O (1) T(n)=2T(n/2)+O(n) a=2 b=2 k=1 T(n)=aT(n/b)+O(nk) T (n) n2 n log n O ( n 1 log n ) = O ( n log n ) n Divide y vencerás. Divide y vencerás. 1. Método. 2. Un ejemplo sencillo. 3. Complejidad del método. 4. Ejemplo: El máximo subarray. 5. Ejemplo: Multiplicación de enteros. 37 Ejemplo: Multiplicación de enteros. Problema: "Dados dos números enteros X e Y de n bits cada uno, calcular su producto” Algoritmo tradicional: Ejemplo en decimal: 12 x 13 36 12 156 Divide y vencerás. 1100 x 1101 1100 0000 1100 1100 10011100 Complejidad: O ( n 2 ) 38 Ejemplo: Multiplicación de enteros. Algoritmo alternativo 1: n bits X X1 Ejemplo en decimal: n / 2 bits n / 2 bits X0 149238 149 238 X = X1 2n/2 + X0 149238 = 149 106/2 + 238 149000 + 238 149238 Divide y vencerás. 39 Ejemplo: Multiplicación de enteros. Los números a multiplicar se pueden representar así: X = X1 2 n / 2 + X0 Y = Y1 2 n / 2 + Y0 … el producto sería: X Y = ( X1 2 n / 2 + X0 ) ( Y1 2 n / 2 + Y0 ) … operando: X Y = X1 Y1 2 n + ( X1 Y0 + X0 Y1 ) 2 n / 2 + X0 Y0 Divide y vencerás. 40 Ejemplo: Multiplicación de enteros. + + + X Y = X1 Y1 2 n + ( X1 Y0 + X0 Y1 ) 2 n / 2 + X0 Y0 x x x x 3 sumas O(n) 2 desplazamientos O(n) 4 multiplicaciones T(n) = 4 T(n/2) + O(n) a=4 b=2 k=1 4 > 21 O ( n log 4) = O ( n 2) 2 Divide y vencerás. 41 Ejemplo: Multiplicación de enteros. Algoritmo alternativo 2: Ecuación obtenida por el método anterior: X Y = X1 Y1 2 n + ( X1 Y0 + X0 Y1 ) 2 n / 2 + X0 Y0 ( X1 – X0 ) ( Y0 – Y1 ) + X1 Y1 + X0 Y0 X Y = X1 Y1 2 n + (( X1 – X0 )( Y0 – Y1 ) + X1 Y1 + X0 Y0 ) 2 n / 2 + X0 Y0 Divide y vencerás. 42 Ejemplo: Multiplicación de enteros. + + + + + + X Y = X1 Y1 2 n + (( X1 – X0 )( Y0 – Y1 ) + X1 Y1 + X0 Y0 ) 2 n / 2 + X0 Y0 x x x x x Iguales Iguales 6 sumas (restas) O(n) 2 desplazamientos O(n) 5 3multiplicaciones multiplicaciones T(n) = 3 T(n/2) + O(n) a=3 b=2 k=1 3 > 21 O ( n log 3) = O ( n 1,59) 2 Divide y vencerás. 43