Your SlideShare is downloading. ×
Divide y Venceras
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Divide y Venceras

8,939
views

Published on

divide y venceras, teoria algoritmica

divide y venceras, teoria algoritmica

Published in: Education, Technology

1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total Views
8,939
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
151
Comments
1
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 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.
  • 2. 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, p 1 , p 2 , ..., p k )
    • para i = 1, 2, ..., k
    • s i = resolver (p i )
    • solucion = combinar (s 1 , s 2 , ..., s k )
    • 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
  • 3. 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.
  • 4. 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));
  • 5. Análisis de tiempos de ejecución
    • Para el esquema recursivo, con división en dos subproblemas:
    • g(n) Si n  n 0 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.
  • 6. Análisis de tiempos de ejecución
    • Desarrollando tenemos:
    • Suponiendo que n es potencia de 2, n = 2 k , y n 0 = n/2 m .
    • Si n 0 =1, entonces m=k:
  • 7. 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(n 2 ) y la combinación en O(n).
      • g(n) = c·n 2 ; f(n) = d·n
  • 8. 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 = b k  k = log b n
      • t(b k ) = a·t(b k-1 ) + d·b k
      • Podemos deducir que:
      • O(n log b a ) 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(n log 2 4 ) = O(n 2 )
  • 9. 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
  • 10. 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
    • en otro caso
    • Min = Min2
    • /*Caso base*/
    • en otro caso si i=j-1
    • si A[i]>A[j]
    • Max = A[i] ; Min = A[j]
    • en otro caso
    • Max = A[j] ; Min= A[i]
    • en otro caso
    • Max = A[i] ; Min = Max
  • 11. 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 = 2 k , tenemos:
    • t(k) = 2·t(k-1) + 2  (x-2)·(x-1) = 0  t(n) = C 1 n + C 2
    • 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?
  • 12. 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.
  • 13. 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)
  • 14. 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[i a ]  A[l]  A[j a ], para i a = i..l-1, j a =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.
  • 15. 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)
    • repetir
    • l = l-1
    • hasta (A[l]  p)
    • mientras k < l
    • intercambiar (k, l)
    • repetir
    • k = k+1
    • hasta (A[k] > p)
    • repetir
    • l = l-1
    • hasta (A[l]  p)
    • Intercambiar (i, l)
  • 16. 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(n 2 )
    • Caso promedio.
    • Se puede comprobar que t p (n)   (n·log n).
  • 17. 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)
  • 18. 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(n 2 )
  • 19.
    • 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(n 2 ).
    Multiplicación rápida de enteros largos
  • 20. Multiplicación rápida de enteros largos
    • 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 = 10 2S ·w·y + 10 S ·(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(n log 2 4 ) = O(n 2 ), no mejora el método clásico.
     n/2   n/2  =S u = w·10 S + x v = y·10 S + z w x u y z v
  • 21. Multiplicación rápida de enteros largos
    • Multiplicación rápida de enteros largos (Karatsuba y Ofman):
    • u·v = 10 2S ·w·y + 10 S ·[(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(n log 2 3 )  O(n 1.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.
  • 22. 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(n 3 ).
    • Aplicando divide y vencerás , cada matriz es dividida en cuatro submatrices de tamaño (n/2)x(n/2): A ij , B ij y C ij .
    x =
    • Es necesario resolver 8 problemas de tamaño n/2. La combinación de los resultados requiere un tiempo de O(n 2 ).
    • t(n) = 8·t(n/2) + a·n 2
    • Resolviéndolo obtenemos que t(n) es O(n 3 ).
    C 11 = A 11 B 11 + A 12 B 21 C 12 = A 11 B 12 + A 12 B 22 C 21 = A 21 B 11 + A 22 B 21 C 22 = A 21 B 12 + A 22 B 22 A 11 A 12 A 22 A 21 B 11 B 12 B 22 B 21 C 11 C 12 C 22 C 21
  • 23. Multiplicación rápida de matrices
    • Multiplicación rápida de matrices (Strassen):
    • P = (A 11 +A 22 )(B 11 +B 22 )
    • Q = (A 12 +A 22 ) B 11 C 11 = P + S - T + U
    • R = A 11 (B 12 -B 22 ) C 12 = R + T
    • S = A 22 (B 21 -B 11 ) C 21 = Q + S
    • T = (A 11 +A 12 )B 22 C 22 = P + R - Q + U
    • U = (A 21 -A 11 )(B 11 +B 12 )
    • V = (A 12 -A 22 )(B 21 +B 22 )
    • El tiempo de ejecución será:
    • t(n) = 7·t(n/2) + a·n 2
    • Resolviéndolo, tenemos que t(n)  O(n log 2 7 )  O(n 2.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.

×