Divide y vencerás Divide y vencerás • Técnica de diseño de algoritmos que consiste en descomponer los casos complejos en casos más pequeños y fáciles de resolver, y combinar las soluciones obtenidas para construir la solución del problema original Ejemplos • Exponenciación ¿cómo calcular eficientemente ak? La forma natural es realizando k-1 multiplicaciones. Esto puede mejorarse viendo que cuando k es par, ak=(ak/2)2 si k 0 1 k /2 2 k a (a ) si k es par a(a k 1 ) si k es impar Ejemplos • QSort Ejemplos • Búsqueda de la mediana Requiere ordenar los elementos (O(n log n)) y luego seleccionar el elemento central Otro problema parecido es conseguir el n-ésimo elemento más pequeño de un arreglo Si existiera la función seleccionar(A,n), calcular la mediana se limitaría a una llamada a esa función Ejemplos • Búsqueda de la mediana La función seleccionar también puede construirse en base a la función mediana Recordemos la función pivote(A,p,k,l) que se utiliza en QuickSort que utiliza p como pivote del arreglo A, haciendo que los elementos menores a p estén en las posiciones 0..k-1 y los elementos mayores en las posiciones l..n-1 Ejemplos • Búsqueda de la mediana Pueden suceder ahora tres casos: 1. s=k: el elemento buscado es p 2. s < k: el elemento buscado está en la mitad izquierda de A 3. s > k: el elemento buscado está en la mitad derecha de A Ejemplos • Iterativamente: funcion seleccion(A,s) i=0; j=n-1; mientras verdad p = mediana(A[i..j]) pivote(A[i..j],p,k,l) si s<k entonces j=k; // buscar ahora en el lado izq sino si s>l entonces i=l; // buscar en el lado derecho sino retornar p; // bingo! fsi fmientras ffuncion Ejemplos • Cada llamada a mediana es de O(n log n), pero el algoritmo se comporta igual si usamos como pivote cualquier elemento del arreglo, en particular p=A[i]; • Luego, mediana se reduce a: retornar seleccion(A, n/2); Ejemplos • Multiplicación • La multiplicación tradicional de números enteros tiene O(N^2) • Sin embargo, esto puede mejorarse • Por ejemplo, 324 x 1390: • 0324 x 1390 podemos separarlo como w=03, x=24, y=13, z=90 Ejemplos • 0324 x 1390 podemos separarlo como w=03, x=24, y=13, z=90 • Podemos ver que: • 324 = 102w+x • 1390 = 102y+z • Luego: • 324x1390 = (102w+x)(102y+z)= 104wy+102(w+y)+xz Ejemplos • 324x1390 = (102w+x)(102y+z)= 104wy+102(w+y)+xz • Ahora hagamos: • r = (w+x)(y+z)=wy+wz+xy+xz • p= wy • q= xz • Finalmente podemos calcular el resultado como 104p+102(r-p-q)+q Ejemplos • Hemos reducido 16 multiplicaciones originalmente a únicamente 3 (obviando las multiplicaciones por potencias de 10) • En general, si los números tienen n dígitos podemos separarlos en números de n/2 dígitos • Las 3 multiplicaciones que aparecen se hacen de la misma forma hasta llegar a números pequeños que puedan manejarse fácilmente Ejemplos • Multiplicación de matrices de Strassen • Sean A y B dos matrices de nxn y sea C = A x B • El algoritmo clásico de multiplicación de matrices es de O(n^3) • Strassen logró mejorar este tiempo a finales de los 60 aplicando un principio parecido al usado anteriormente para números enteros Ejemplos • Multiplicación de matrices de Strassen Ejemplos • Multiplicación de matrices de Strassen • Este algoritmo permite mejorar la multiplicación de matrices de O(N^3) a O(N^2.807) • Actualmente el algoritmo de CoppersmithWinograd (2008) permite multiplicar matrices en O(N^2.376) • Sin embargo, para obtener ventajas las matrices deben ser realmente grandes