CC30A Algoritmos y Estructuras de Datos Universidad de Chile Facultad de Ciencias Físicas y Matemáticas Escuela de Ingeniería y Ciencias CC30A Algoritmos y Estructuras de Datos Dividir para reinar Tabulación
Dividir para reinar Multiplicación de dos polinomios Problema: multiplicar dos polinomios de grado n-1. A(x)=a0+a1x+a2x2+…+an-1xn-1 B(x)=b0+b1x+b2x2+…+bn-1xn-1 C=A(x)*B(x).
Dividir para reinar Multiplicación de dos polinomios Solución trivial O(n2): float[] c=new float[2*n-1]; // inicializar c[k] en 0 for (i=0; i<n: ++i) for (j=0; j<n; ++j) c[i+j]+=a[i]*b[j];
Dividir para reinar Multiplicación de dos polinomios Algoritmo más eficiente: separar cada polinomio en 2 partes. Ejemplo:
Dividir para reinar Multiplicación de dos polinomios En general: El grado de cada polinomio de la suma es (n/2)-1.
Dividir para reinar Multiplicación de dos polinomios Por lo tanto: Esto se puede implementar con 4 multiplicaciones de polinomios de tamaño n/2, más kn sumas (para algún k).
Dividir para reinar Multiplicación de dos polinomios El número total de operaciones T(n) se puede escribir como: ¿Qué complejidad temporal tiene el algoritmo?
Dividir para reinar Multiplicación de dos polinomios Se resolverá la ecuación: “Desenrollando” la ecuación:
Dividir para reinar Multiplicación de dos polinomios En general: Si p>q (nuestro caso):
Dividir para reinar Multiplicación de dos polinomios Escoger j tal que qj=n (o sea, j=logqn): Pero:
Dividir para reinar Multiplicación de dos polinomios Por lo tanto, el algoritmo demora: Aplicando el resultado a nuestra ecuación, donde p=4 y q=2: El resultado no es muy interesante…
Dividir para reinar Multiplicación de dos polinomios PERO si se calcula: Entonces: Requiere 3 multiplicaciones recursivas.
Dividir para reinar Multiplicación de dos polinomios Por lo tanto: Ejercicio: demostrar T(n) en los casos: p<q = O(n) p=q = (n log n)
Recursividad y tabulación No siempre la recursividad es eficiente. Ejemplo: cálculo de números de Fibonacci.
Recursividad y tabulación Tabla de valores:
Recursividad y tabulación Solución recursiva: int F(int n) { if (n<=1) return n; else return F(n-1)+F(n-2); }
Recursividad y tabulación Esto resulta muy ineficiente. Si T(n) representa el número de sumas ejecutadas para calcular fn, se tiene: T(0)=0 T(1)=0 T(n)=1+T(n-1)+T(n-2)
Recursividad y tabulación Tabla de valores para T(n): ¿T(n)=fn-1? Si. (Ejercicio: demostrarlo).
Recursividad y tabulación Luego, el tiempo crece de manera exponencial (muy lento). El problema es que se está recalculando una y otra vez los mismos valores (ver dibujo en pizarra). Una forma de evitar esto es anotar los valores calculados en un arreglo.
Recursividad y tabulación El arreglo debe llenarse de manera ordenada: int F(int n) { int fib[n+1]; fib[0]=0; fib[1]=1; for (i=2; i<=n; ++i) fib[i]=fib[i-1]+fib[i-2]; }
Recursividad y tabulación Tiempo del nuevo algoritmo: O(n). Esta idea se llama programación dinámica cuando se usa para resolver problemas de optimización. ¿Es posible calcular fn más rápido que O(n)? Respuesta: Si.
Recursividad y tabulación Se tiene que: Se define una función auxiliar g tal que:
Recursividad y tabulación Con esto se plantea el siguiente sistema de ecuaciones:
Recursividad y tabulación An-1 se puede calcular por el método eficiente => Tiempo: O(log n).