Divide y vencerás 1. Método general.

Slides:



Advertisements
Presentaciones similares
Diseño y análisis de algoritmos
Advertisements

Diseño y análisis de algoritmos
Diseño y análisis de algoritmos
Diseño y análisis de algoritmos
Complejidad de Algoritmos
¿ Que es la complejidad de un algoritmo ?
Bloque 2: Divide y Vencerás
UNIVERSIDAD LATINA (UNILA) IV. IMPLANTACION DE ALGORITMOS.
DETERMINANTES DE UNA MATRIZ
Investigación Operativa
Sistema de tres ecuaciones con tres incógnitas
JOCELYN DÁVILA HERNÁNDEZ JORGE QUECHOLAC ZAMBRANO.
Tema 2: Métodos de ajuste
DPTO. MATEMÁTICAS - I.E.S. PABLO SERRANO
Ecuaciones de recurrencia
TRANSFORMACIONES LINEALES PARA REDES NEURALES ARTIFICIALES
Análisis de Algoritmos
Complejidad Programación II de febrero de 2009.
Algoritmos.

Algoritmos de búsqueda
Estructura de Datos II Equipo 4 Equipo 7 Acosta Montiel Miguel A.
Descomposición Factorial Unidad 5
Parte II. Algorítmica. 3. Algoritmos voraces.
Inversa de una matriz.
Resolución de recurrencias, por cambio de variable
Radicales y sus operaciones
Backtracking 1. Método general. 2. Análisis de tiempos de ejecución.
4.  Métodos matemáticos.
1. Desarrollo de Programas iterativos usando invariante
Operaciones con números complejos
Parte II. Algorítmica. 4. Programación dinámica.
ELO3201 Análisis de Algoritmos (Cont.) Agustín J. González ELO320 1º sem 2004.
Parte I. Estructuras de Datos.
SIG. LAURA VELAZQUEZ MORELOS. Hace referencia a un refrán que implica resolver un problema difícil, dividiéndolo en partes más simples tantas veces como.
Multiplicación de matrices
1  Una Ecuaci ó n de Recurrencia Lineal de Orden n a Coeficientes Constantes se define seg ú n la ecuaci ó n: ∑ d K a K = g(n) donde d K son constantes.
1 Ordenamiento en tiempo lineal y Estadísticas de orden Agustín J. González ELO320: Estructura de Datos y Algoritmos 1er. Sem 2002.
Algoritmos de Ordenamiento y Complejidad
Parte I. Estructuras de Datos.
M.C. Meliza Contreras González 1.  Es normal que un algoritmo se base en procedimientos auxiliares, haga llamadas recursivas para tamaños menores o reduzca.
Tema 11: Programación dinámica
Parte I. Estructuras de Datos.
Capítulo 6. ANÁLISIS DE ALGORITMOS
Análisis de Algoritmos
Tema 10: Algoritmos voraces
ELO3201 Análisis de Algoritmos (cont.) Agustín J. González ELO320 1º sem 2002.
1 Condiciones de extremo Proceso para derivar las condiciones De problema más simple a más complejo Progresión de problemas: Problema sin restricciones.
Departamento de Sistemas Informáticos y Programación Universidad Complutense de Madrid Bloque 2: Divide y Vencerás Unidad 1: Nociones básicas.
OPERATORIA DE LOS NÚMEROS RACIONALES
Oscar F. Bedoya L. Fundamentos de análisis y diseño de algoritmos.
Ordenamiento en lenguaje c
Matriz inversa Método Gauss Jordan.
Diseño y análisis de algoritmos Análisis de Algoritmos II.
FACTORIZACION.
METODOS DE BUSQUEDA EN C++ Oscar Michel Ruiz León
METODO DE SUMA Y RESTA. INDICE.
UPC MA112 (EPE) Tema: Matriz Inversa
Introducción a los TADs
Recopiló: César Johnson Cruz
MATRIZ INVERSA.
75.41 Algoritmos y Programación II Cátedra Ing. Patricia Calvo Complejidad algorítmica.
Matemática Básica (Ing.) 1 Sesión 12.1 Sistemas lineales y método de Gauss.
Números racionales Lorenzo Contreras Garduño Ago. 2015
ENRIQUE MALDONADO MUÑOZ JESUS CABALLERO LUNA IRVING GONZÁLEZ VÁZQUEZ.
Programación Dinámica  La programación dinámica se suele utilizar en problemas de optimización, donde una solución está formada por una serie de decisiones.
Números y Fracciones 1.Los números naturales y los enterosLos números naturales y los enteros 2.Números primosNúmeros primos 3.Máximo común divisor y mínimo.
LE, EI, Profesor Ramón Castro Liceaga UNIVERSIDAD LATINA (UNILA) IV. IMPLANTACION DE ALGORITMOS.
Divide y vencerás 1. Método general.
Transcripción de la presentación:

Divide y vencerás 1. Método general. 2. Análisis de tiempos de ejecución. 2.1. Análisis general. 2.2. Caso recursivo. 3. Ejemplos. 3.1. Búsqueda del máximo y el mínimo. 3.2. Ordenación por mezcla y ordenación rápida. 3.3. El problema de selección. 3.4. Multiplicación rápida de enteros largos. 3.5. Multiplicación rápida de matrices. 1

Método general La técnica divide y vencerás consiste en descomponer el problema en un conjunto de subproblemas más pequeños. Después se resuelven estos subproblemas y se combinan las soluciones para obtener la solución para el problema original. Esquema general: divide_venceras (p: problema) dividir (p, p1, p2, ..., pk) para i = 1, 2, ..., k si = resolver (pi) solucion = combinar (s1, s2, ..., sk) Puede ser recursivo siendo “resolver” una nueva llamada a “divide_venceras” Si el problema es “pequeño”, entonces se puede resolver de forma directa. Ejemplo: Torres de Hanoi 2

Método general Para que pueda aplicarse la técnica divide y vencerás necesitamos: El problema original debe poder dividirse fácilmente en un conjunto de subproblemas, del mismo tipo que el problema original pero con una resolución más sencilla (menos costosa). La solución de un subproblema debe obtenerse independientemente de los otros. Normalmente los subproblemas deben ser de tamaños parecidos. Como mínimo necesitamos que haya dos subproblemas. Si sólo tenemos un subproblema hablamos de técnicas de reducción (o simplificación). Necesitamos un método (más o menos directo) de resolver los problemas de tamaño pequeño. Es necesario tener un método de combinar los resultados de los subproblemas. 3

Método general, esquema recursivo Normalmente para resolver los subproblemas se utilizan llamadas recursivas al mismo algoritmo (aunque no necesariamente). Esquema recursivo (con división en 2 subproblemas): divide_venceras (p, q: indice) var m: indice si pequeño (p, q) solucion = solucion_directa (p, q) en otro caso m = dividir (p, q); solucion = combinar (divide_venceras (p, m), divide_venceras (m+1, q)); 4

Análisis de tiempos de ejecución Para el esquema recursivo, con división en dos subproblemas: g(n) Si nn0 es suficientemente pequeño t(n) = 2*t(n/2) + f(n) En otro caso t(n): tiempo de ejecución del algoritmo. g(n): tiempo de comprobar si es pequeño y calcular la solución para el caso base f(n): tiempo de comprobar si es pequeño y de dividir el problema y combinar los resultados. 5

Análisis de tiempos de ejecución Desarrollando tenemos: Suponiendo que n es potencia de 2, n = 2k, y n0 = n/2m. Si n0=1, entonces m=k: 6

Análisis de tiempos de ejecución Ejemplo 1. La resolución directa se puede hacer en un tiempo constante y la combinación de resultados también. g(n) = c; f(n) = d Ejemplo 2. La solución directa se calcula en O(n2) y la combinación en O(n). g(n) = c·n2; f(n) = d·n 7

Análisis de tiempos de ejecución Si el problema se divide en a llamadas recursivas de tamaño n/b, y la combinación requiere f(n) = d·n  O(n), entonces: t(n) = a·t(n/b) + d·n Suponiendo n = bk  k = logb n t(bk) = a·t(bk-1) + d·bk Podemos deducir que: O(nlogba) Si a > b t(n)  O(n·log n) Si a = b O(n) Si a < b Ejemplo 3. Dividimos en 2 trozos de tamaño n/2 (ordenación por mezcla): a = b = 2 t(n)  O(n·log n) Ejemplo 4. Realizamos 4 llamadas recursivas con trozos de tamaño n/2. a = 4; b = 2 t(n)  O(nlog24) = O(n2) 8

Búsqueda del máximo y del mínimo Método directo: MaxMin (A: array [1..N] of tipo; var Max, Min: tipo) Max = A[1] Min = A[1] para i=2, 3, ..., N si A[i]>Max Max = A[i] en otro caso si A[i]<Min Min = A[i] Contamos el número de comparaciones y asignaciones. Comparaciones Asignaciones 9

Búsqueda del máximo y del mínimo Aplicando divide y vencerás: MaxMinDV (i, j: integer; var Max, Min: tipo) si i<j-1 mit = (i+j) div 2 MaxMinDV (i, mit, Max1, Min1) MaxMinDV (mit+1, j, Max2, Min2) /*Combinar*/ si Max1>Max2 Max= Max1 en otro caso Max = Max2 si Min1<Min2 Min = Min1 Min = Min2 /*Caso base*/ en otro caso si i=j-1 si A[i]>A[j] Max = A[i] ; Min = A[j] Max = A[j] ; Min= A[i] Max = A[i] ; Min = Max 10

Búsqueda del máximo y del mínimo Comparaciones (entre valores del tipo a ordenar) usando divide y vencerás. Debemos resolver la ecuación de recurrencia: t(n) = 2·t(n/2) + 2 Suponiendo n = 2k, tenemos: t(k) = 2·t(k-1) + 2  (x-2)·(x-1) = 0  t(n) = C1n + C2 Con condiciones iniciales t(2) = 1; t(4) = 4 t(n) = 3/2·n – 2 Con condiciones iniciales t(1) = 0; t(2) = 1 t(n) = n – 1 ¿Cuál es el valor de o? 11

Búsqueda del máximo y del mínimo Asignaciones. La ecuación de recurrencia es la misma, sólo cambian las condiciones iniciales. t(2) = 2; t(4) = 6 Número de asignaciones: t(n) = 2n – 2 El número de comparaciones es menor en el caso promedio. El número de asignaciones es peor en todos los casos. 12

Ordenación por mezcla MergeSort (i, j: integer) /* Es pequeño si el tamaño es menor que un caso base */ si pequeño(i, j) OrdenaciónDirecta(i, j) en otro caso /* El array original es dividido en dos trozos de tamaño igual (o lo más parecido posible), es decir n/2 y n/2 */ s = (i + j) div 2 /* Resolver recursivamente los subproblemas */ MergeSort(i, s) MergeSort(s+1, j) /* Mezcla dos listas ordenadas. En O(n) */ Combina (i, s, j) t(n) = t(n/2) + t(n/2) + f(n); Con f(n)  O(n) Suponiendo n potencia de 2, tenemos: t(n) = 2·t(n/2) + a·n + b t(n)  O(n·log n) 13

Ordenación rápida QuickSort (i, j: integer) /* Es pequeño si el tamaño es menor que un caso base */ si pequeño(i, j) OrdenaciónDirecta(i, j) en otro caso /* El array (i..j) es dividido usando un procedimiento Pivote, que devuelve un entero l entre (i, j), tal que A[ia]  A[l]  A[ja], para ia = i..l-1, ja=l+1..j */ Pivote(i,j,l) /* Resolver recursivamente los subproblemas, sin incluir el pivote */ QuickSort(i, l-1) QuickSort(l+1, j) /* No es necesario combinar */ Aunque no hay coste de combinar los resultados, la llamada a Pivote tiene un coste O(n). Las particiones no tienen porqué ser de tamaño n/2. 14

Ordenación rápida Pivote (i, j: integer; var l: integer) p = A[i] k = i l = j+1 repetir k:= k+1 hasta (A[k] > p) o (k  j) l = l-1 hasta (A[l]  p) mientras k < l intercambiar (k, l) k = k+1 hasta (A[k] > p) Intercambiar (i, l) 15

Ordenación rápida: costes. Mejor caso. Todas las particiones son de tamaño similar, n/2. t(n) = 2·t(n/2) + b·n + c  (n·log n) Peor caso. Se da cuando la matriz está ordenada o inversamente ordeanada. En este caso una partición tiene tamaño 0 y la otra n-1. t(n) = t(n-1) + b·n + c  O(n2) Caso promedio. Se puede comprobar que tp(n)  (n·log n). 16

El problema de selección Sea T[1..n] un array (no ordenado) de enteros, y sea s un entero entre 1 y n. El problema de selección consiste en encontrar el elemento que se encontraría en la posición s si el array estuviera ordenado. Si s = n/2, entonces tenemos el problema de encontrar la mediana de T, es decir el valor que es mayor que la mitad de los elementos de T y menor que la otra mitad. Forma sencilla de resolver el problema de selección: Ordenar T y devolver el valor T[s]. Esto requeriría (n·log n) 17

El problema de selección Utilizando el procedimiento Pivote podemos resolverlo en O(n). Selección (T: array [1..n]; s: integer) i = 1 j = n repetir Pivote (i, j, l) si s < l j = l-1 en otro caso si s > l i = l+1 hasta l=s devolver T[l] El procedimiento es no recursivo. Además es una reducción: el problema es descompuesto en un solo subproblema de tamaño menor. En el mejor caso, el subproblema es de tamaño n/2: t(n) = t(n/2) + a·n; t(n)  O(n) En el peor caso el subproblema es de tamaño n-1: t(n) = t(n-1) + a·n; t(n)  O(n2) 18

Multiplicación rápida de enteros largos Supongamos que representamos números enteros (de tamaño arbitrariamente grande) mediante listas de cifras. tipo EnteroLargo = puntero a nodo; nodo = registro valor : 0..9 sig : EnteroLargo Con el algoritmo clásico de multiplicación, multiplicamos todos los dígitos de un entero por los del otro y sumamos (con los desplazamientos adecuados). El algoritmo tendrá un orden de O(n·m), suponiendo n y m las longitudes de los enteros. Si las suponemos iguales, entonces O(n2). 19

Multiplicación rápida de enteros largos w x u u = w·10S + x y z v v = y·10S + z n/2 n/2=S Podemos aplicar la técnica divide y vencerás: Divide: los enteros de tamaño n son divididos en tamaño n/2. Solucionar los subproblemas de tamaño n/2. Combinar: sumar los resultados de los anteriores (con los desplazamientos adecuados). Cálculo de la multiplicación con divide y vencerás: u·v = 102S·w·y + 10S·(w·z+x·y) + x·z El problema de tamaño n es descompuesto en 4 problemas de tamaño n/2. La combinación (sumas y desplazamientos) se puede realizar en un tiempo lineal O(n). t(n) = 4·t(n/2) + d·n  O(nlog24) = O(n2), no mejora el método clásico. 20

Multiplicación rápida de enteros largos Multiplicación rápida de enteros largos (Karatsuba y Ofman): u·v = 102S·w·y + 10S·[(w-x)·(z-y) + w·y + x·z] + x·z En este caso se requieren 3 multiplicaciones de tamaño n/2: t(n) = 3·t(n/2) + d’·n  O(nlog23)  O(n1.59) El método es asintóticamente mejor que el método clásico. Sin embargo, las constantes son mucho mayores. La combinación es muy costosa. 21

Multiplicación rápida de matrices Multiplicar dos matrices cuadradas A, B de tamaños nxn. C = AxB; C(i, j) =  A(i, k)·B(k, j); Para todo i, j= 1..n k=1..n El método clásico de multiplicación de matrices requiere O(n3). Aplicando divide y vencerás, cada matriz es dividida en cuatro submatrices de tamaño (n/2)x(n/2): Aij, Bij y Cij. C11 = A11B11 + A12B21 C12 = A11B12 + A12B22 C21 = A21B11 + A22B21 C22 = A21B12 + A22B22 A11 A12 A22 A21 B11 B12 B22 B21 C11 C12 C22 C21 x = Es necesario resolver 8 problemas de tamaño n/2. La combinación de los resultados requiere un tiempo de O(n2). t(n) = 8·t(n/2) + a·n2 Resolviéndolo obtenemos que t(n) es O(n3). 22

Multiplicación rápida de matrices Multiplicación rápida de matrices (Strassen): P = (A11+A22)(B11+B22) Q = (A12+A22) B11 C11 = P + S - T + U R = A11 (B12-B22) C12 = R + T S = A22(B21-B11) C21 = Q + S T = (A11+A12)B22 C22 = P + R - Q + U U = (A21-A11)(B11+B12) V = (A12-A22)(B21+B22) El tiempo de ejecución será: t(n) = 7·t(n/2) + a·n2 Resolviéndolo, tenemos que t(n)  O(nlog27)  O(n2.81). Las constantes que multiplican al polinomio son mucho mayores (tenemos muchas sumas), por lo que sólo es mejor cuando la entrada es muy grande. 23