Vous êtes sur la page 1sur 43

Algortmica III

Divide y Vencers
Docente: Carlos A. Ruiz De La Cruz Melo
Correo: zorroculto69@hotmail.com
2
Divide y Vencers
Divide y vencers es una tcnica para disear
algoritmos que consiste en:

Descomponer el caso que haya que resolver en
un cierto nmero de sub-casos ms pequeos
del mismo problema.

Resolver de manera sucesiva e independiente
cada uno de estos sub-casos.

Combinar las soluciones obtenidas de esta
manera para obtener la solucin original.
3
Caso General
Consideremos un problema
arbitrario, y sea caso un algoritmo
sencillo capaz de resolver el
problema.

Se le llama sub-algoritmo bsico.
4
Caso General
algoritmo DivVen(x): tipo de dato
Si (x suficientemente pequeo o sencillo) entonces
retornar caso(x)
finsi
//Descomponer x en casos ms pequeos x
1
,x
2
,.. x
k

para i 1 hasta k hacer
Y
i
DivVen(x
i
)
finpara
//Recombinar los Y
i
para obtener Y de x
para i 1 hasta k hacer
Y Y + Y
i

finpara
retornar Y
finalgoritmo
Algunos algoritmos de divide y
vencers no siguen exactamente este
esquema: por ejemplo, puede necesitar
que el primer subcaso est resuelto
antes de formar el segundo subcaso.

El nmero de sub-ejemplares n,
suele ser pequeo e
independiente del caso particular
que haya que resolver.

Dividir x en sub-ejemplares
algoritmo DivVen(x): tipo de dato
Si (x suficientemente pequeo o sencillo) entonces
retornar caso(x)
finsi
//Descomponer x en casos ms pequeos x
1
,x
2
,.. x
k

para i 1 hasta k hacer
Y
i
DivVen(x
i
)
finpara
//Recombinar los Y
i
para obtener Y de x
para i 1 hasta k hacer
Y Y + Y
i

finpara
retornar Y
finalgoritmo
algoritmo DivVen(x): tipo de dato
Si (x suficientemente pequeo o sencillo) entonces
retornar caso(x)
finsi
//Descomponer x en casos ms pequeos x
1
,x
2
,.. x
k

para i 1 hasta k hacer
Y
i
DivVen(x
i
)
finpara
//Recombinar los Y
i
para obtener Y de x
para i 1 hasta k hacer
Y Y + Y
i

finpara
retornar Y
finalgoritmo
Determinacin del umbral
dnde colocar el umbral?,
esto es, cundo se considera que
un sub-problema es
suficientemente pequeo como
para no tener que dividirlo para
resolverlo

Cuando n = 1, no tiene mucho
sentido descomponer x en un caso
ms sencillo x
1


La mayora de algoritmos de divide y
vencers son tales que el tamao de
los k sub-casos es aproximadamente
(n/k) para alguna constante k, en
donde n es el tamao del caso
original.

k sub-casos
algoritmo DivVen(x): tipo de dato
Si (x suficientemente pequeo o sencillo) entonces
retornar caso(x)
finsi
//Descomponer x en casos ms pequeos x
1
,x
2
,.. x
k

para i 1 hasta k hacer
Y
i
DivVen(x
i
)
finpara
//Recombinar los Y
i
para obtener Y de x
para i 1 hasta k hacer
Y Y + Y
i

finpara
retornar Y
finalgoritmo
8
Combinar las soluciones

El tiempo necesario para
combinar las soluciones de los
sub-problemas para hallar la
solucin del original;
normalmente es O(n
k
). Por
tanto el tiempo total es:





Siempre que n sea
suficientemente grande.
) ( ) ( * ) (
k
n O k n t k n t + =
algoritmo DivVen(x): tipo de dato
Si (x suficientemente pequeo o sencillo) entonces
retornar caso(x)
finsi
//Descomponer x en casos ms pequeos x
1
,x
2
,.. x
k

para i 1 hasta k hacer
Y
i
DivVen(x
i
)
finpara
//Recombinar los Y
i
para obtener Y de x
para i 1 hasta k hacer
Y Y + Y
i

finpara
retornar Y
finalgoritmo
9
Justificacin del Divide y Vencers
Para que se justifique divide y vencers se
necesitan tres condiciones.

Tiene que ser posible descomponer el caso
en sub-casos y recomponer las soluciones
parciales de forma bastante eficiente.

Los sub-casos deben ser en lo posible
aproximadamente del mismo tamao.

La decisin de utilizar el sub-algoritmo bsico
en lugar de hacer llamadas recursivas debe
tomarse cuidadosamente.



Eficiencia de Divide
y Vencers
La eficiencia de esta tcnica
depende de cmo se resuelvan los
sub-casos.
Esquema de la Tcnica de Divide y
Vencers
Divisin.
Divide el problema original en k sub-
problemas de menor tamao

Conquistar.
Estos sub-problemas se resuelven
independientemente:

Directamente si son simples
Reduciendo a casos ms simples
(tpicamente de forma recursiva)

Combinar.
Se combinan sus soluciones parciales para
obtener la solucin del problema original.
12
Recursin
La recursin permite definir un objeto
(problemas, estructuras de datos) en
trminos de s mismo.

Un procedimiento recursivo debe tener:

Un criterio llamado criterio bsico,
por el que el mtodo no se llame a s
mismo, sino que llegue a una
solucin directa.

Cada vez que el mtodo se llame a
s mismo (directa o indirectamente),
debe estar ms cerca del criterio
base.
13
Tipos de Recursin
Recursin Directa:

El subprograma se llama directamente
a s mismo.
Llamada a P
Sub Programa P
14
Tipos de Recursin
Recursin Indirecta
El subprograma llama a otro
subprograma, y ste a su vez llama al
primero de lo contrario a un tercero.
Llamada a Q
Llamada a V
Sub Programa P
Sub Programa Q
Sub Programa V
Llamada a Q
Llamada a P
Sub Programa P
Sub Programa Q
15
Propiedades de la Recursin
Un procedimiento recursivo con
criterio base y aproximacin
constante a este criterio base, se dice
que est bien definido.

Se dice profundidad recursiva al
nmero de veces que se llama
recursivamente un subprograma.

La representacin en forma grfica se
puede realizar por medio de un rbol
recursivo.



16
Funcionamiento Interno de la
Recursin
Cuando un programa llama a un
subprograma, debe guardarse varios
elementos:

Debe guardarse los valores de los
parmetros del subprograma que
llama; para poder encontrarlos
despus que retorna el control a
este subprograma.

Debe guardarse la direccin de la
instruccin que se debe ejecutar a
continuacin del subprograma
llamado, para retornar el control a
esta instruccin.
17
Funcionamiento Interno de la
Recursin
Pila

Es una lista de elementos a la cual se le
puede insertar o eliminar elementos, slo
por uno de sus extremos. (LIFO)


Internamente se utiliza una estructura
tipo pila, que guardar una copia de los
valores de variables y constantes
locales del subprograma que efecta la
llamada.

Adems, se guarda una referencia a la
siguiente instruccin a ejecutar.
Proceso
18
Funcionamiento Interno de la
Recursin
Se procede a ejecutar las
instrucciones del subprograma
llamado.

Concluida la ejecucin del
subprograma llamado, se
recupera la copia de los valores
del tope de la pila.

Se retorna el control a la
direccin de la siguiente
instruccin a ejecutar, para
continuar operando.

Esto se repite hasta que la pila
est vaca.
Proceso
funcin m(3)
funcin m(2)
funcin m(1)

m(1)
m(2)
m(3)
P
I
L
A
Exponenciacin
Un ejemplo ms sencillo de la tcnica divide y
vencers que no deja de ser interesante es un
algoritmo que calcula la potencia a
n
. para un
entero a y un natural n. La versin ms ingenua
de dicho algoritmo es la siguiente:
Algoritmo potencia(a, n)
resu 1
para x 1 hasta n hacer
resu resu * a
finpara
retornar resu
fincnumero
resu= a
n

Exponenciacin
Si bien el costo de una
multiplicacin vara
considerablemente con el
tamao de los nmeros a
multiplicar, concentremos por
ahora la atencin en contar el
nmero de multiplicaciones
que realiza este algoritmo en
funcin de n sin preocuparnos
por el tamao de los nmeros
a multiplicar.

Evidentemente el nmero de
multiplicaciones es n.

Este algoritmo requiere un
tiempo que est en u(n).
Algoritmo potencia(a, n) : entero
resu 1
para x 1 hasta n hacer
resu resu * a
finpara
retornar resu
fincnumero
Escribiendo de otra manera
Exponenciacin
Se puede hacer algo mejor? S,
utilizando la tcnica de divide y
vencers y observando que para
n par a
n
= (a
n /2
)
2
.

Esto nos permite escribir la funcin
anterior de otra manera:
Algoritmo potencia2(a, n) : entero
si n=0 entonces
resu 1
sino si n es par entonces
resupotencia2(a, n/2)
resu resu * resu
sino
resua* potencia2(a, n-1)
finsi
finsi
retornar resu
Fincnumero
Exponenciacin
Algoritmo potencia2(a, n) : entero
si n=0 entonces
resu 1
sino si n es par entonces
resupotencia2(a, n/2)
resu resu * resu
sino
resua* potencia2(a, n-1)
finsi
finsi
retornar resu
Fincnumero
Sea N(n) el nmero de multiplicaciones
realizadas por este algoritmo para el exponente
n.

Si n es par, N(n) = N(n/2)+1. sta es una
recurrencia divide y vencers con a = 1, b = 2 y
k= 0.

Por ello, a = b
k
y N(n) e u (log n) para n
mltiplo de 2. Se puede comprobar que el mismo
resultado se obtiene para los dems ns.
Exponenciacin
Comparado con el mtodo original de multiplicar x por
s mismo n veces, este algoritmo slo utiliza O(log n)
multiplicaciones y acelera el clculo de a
n

tremendamente; ms o menos de la misma forma que
el algoritmo de la multiplicacin acelera una
multiplicacin sobre el mtodo ms lento de realizar
una suma repetida.
Algoritmo potencia2(a, n) : entero
si n=0 entonces
resu 1
sino si n es par entonces
resupotencia2(a, n/2)
resu resu * resu
sino
resua* potencia2(a, n-1)
finsi
finsi
retornar resu
Fincnumero
Multiplicacin de
nmeros grandes
Como afirmamos recin, no es lo mismo
multiplicar nmeros pequeos que
nmeros grandes. Repasemos con un
ejemplo el algoritmo de multiplicacin
usual:
3476
1593
10428
31284
17380
3476
5537268
Multiplicacin de
nmeros grandes
3476
1593
10428
31284
17380
3476
5537268
Por cada dgito de 1593 escribimos un
trmino a sumar.

Para el cmputo de cada termino,
debemos recorrer los dgitos de 3476.

Sea n el nmero de dgitos de los
nmeros a multiplicar (asumiendo que
los factores tienen aproximadamente el
mismo nmero de dgitos).

El cmputo de las n lneas insume
tiempo u(n
2
), y la suma de los n
trminos tambin. se es el orden del
algoritmo usual de multiplicacin.
Aplicando Divide y Venceras
Separemos cada factor en dos mitades: el
primero en 34 y 76, y el segundo en 15
y 93:

34 * 15 = 510 0000
34 * 93 = 3162 00
76 * 15 = 1140 00
76 * 93 = 70 68
5537268
Esta es una manera correcta de multiplicar dado que

3476 = 10
2
*34 + 76 y 1593 =10
2
*15 + 93,

luego

3476*1593 = 10
4
* (34*15) + 10
2
* (34* 93 + 76*15) + 76*93.
En general queremos multiplicar 2 nmeros a y b de n
dgitos decimales. Asumimos por simplicidad que n es
par.

El mtodo que estamos considerando descompone a y
b:

a = 10
n/2
w +x y b = 10
n/2
y +z. Luego, a *b = 10
n
wy +10

n/2
(wz +xy)+xz.

Es decir, para realizar una multiplicacin entre nmeros
de longitud decimal n se realizan 4 multiplicaciones entre
nmeros de longitud decimal n/2, adems de 3 sumas
de nmeros de longitud decimal n y multiplicaciones por
potencias de 10, que no son verdaderas multiplicaciones
sino slo desplazamientos hacia la izquierda, o
equivalentemente, el simple agregado de 0s a la
derecha
Aplicando Divide y Venceras
34 * 15 = 510 0000
34 * 93 = 3162 00
76 * 15 = 1140 00
76 * 93 = 7068
5537268
Vale decir que se reduce el problema de
realizar una multiplicacin entre nmeros de
longitud n al de realizar 4 multiplicaciones entre
nmeros de longitud n/2 ms ciertas
operaciones (sumas, shifts) que son de orden
u(n).

Para analizar este algoritmo, consideramos la
recurrencia resultante:
Aplicando Divide y Venceras
t(n) = 4t(n/2) + u(n)
Como 4 > 2
1
, resulta que t(n)eu (n
log
2
4
) = u(n
2
). Es
decir, no hemos ganado nada sobre el algoritmo
original, el que todos utilizamos en la prctica.
34 * 15 = 510
34 * 93 = 3162
76 * 15 = 1140
76 * 93 = 7068
5537268
Sin embargo, ste es fcil de mejorar.
Llamemos p = wy, q = xz y r = (w+x)(y+z).

Con slo 3 multiplicaciones entre nmeros
de longitud n/2 (o n/2+1 en el ltimo caso)
obtenemos p, q y r.

Observemos adems que r resulta igual a
r = wy +wz +xy +xz =p+wz +xy +q.

Por ello, a*b = 10
n
p+10
n/2
(rpq)+q, es
decir, 3 multiplicaciones y varias sumas y
restas. La recurrencia asociada a este
algoritmo es:
Aplicando Divide y Venceras
t(n) = 3t(n/2) + u(n)
34 * 15 = 510
34 * 93 = 3162
76 * 15 = 1140
76 * 93 = 7068
5537268
Aplicando Divide y Venceras
Como an tenemos 3 > 2
1
, resulta que
t(n) eu(n
log
2
3
). Esto es t(n) eO(n
1.6
) y
t(n)e O (n
1.5
). Es decir, este algoritmo
es significativamente mejor que el que
utilizamos en la prctica.
t(n) = 3t(n/2) + u(n)
34 * 15 = 510
34 * 93 = 3162
76 * 15 = 1140
76 * 93 = 7068
5537268
Factoriales
El factorial de un nmero entero positivo n
se define como el producto de los nmeros
comprendidos entre 1 y n. La expresin n!
simboliza el factorial de n.

>
=
=
1 )! 1 ( *
1 1
) (
n n n
n
n f
Mtodo factorial(nvalor)
si (nvalor 1) entonces
retornar 1 // estado bsico
sino
retornar nvalor*factorial(nvalor-1)
fsi
finfactorial
Factoriales
Mtodo factorial(nvalor)
si (nvalor 1) entonces
retornar 1 // estado bsico
sino
retornar nvalor*factorial(nvalor-1)
fsi
finfactorial
Para las primeras instrucciones cuando nValor es 1 0 tenemos O(1)

Para la llamada recursiva tenemos T(n) = 1 + T(n-1) para nValor > 1 ... (A)

Si suponemos que n = n-1 en (A) T(n-1) = 1 + T(n-2) ....(B)

Remplazando lo anterior en (A): T(n) = 1 + 1 + T(n-2) = 2 + T(n-2) .... (C)

Por tanto tenemos: T(n) = 2 + T(n-2) para nValor > 2 ...(C)
Factoriales
Mtodo factorial()
si (nvalor 1) entonces
retornar 1 // estado bsico
sino
retornar nvalor*factorial(nvalor-1)
fsi
finfactorial
Si suponemos que n = n-2 en (A) T(n-2) = 1 + T(n-3) ... (D)

Remplazando lo anterior en (C): T(n) = 2 + 1 + T(n-3) = 3 + T(n-3) ... (D)

En la siguiente llamada tenemos: T(n) = 3 + T(n-3) para nValor > 3 ... (D)

Por tanto en la penltima llamada tenemos: T(n) = (n-1) + T(1)

Con lo cual T(n) = n 1 +1 = n

Concluyendo con O(n)
PASO N PILA RETORNO PROX.
0 4 4
1 4 4*, 3
2 3 4*,3*, 2
3 2 4*,3*,2*, 1
4 1 4*,3*,2*,1*, 0
5 0 4*,3*,2*,1*, 1 1
6 1 4*,3*,2*, 1(1*1) 2
7 2 4*,3*, 2(2*1) 3
8 3 4*, 6(3*2) 4
9 4 24(4*6)
Funcionamiento Interno de la
Recursin
Calculo recursivo del
Factorial(n=4)
Fibonacci
La determuinacin de la serie Fibonacci: 0, 1 ,1, 2, 3, 5, 8, 13, 21 ....se
obtiene de la suma de los dos nmeros anteriores. Es decir:
Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = Fibonacci(1) + Fibonacci(0) = 1 + 0 = 1
Fibonacci(3) = Fibonacci(2) + Fibonacci(1) = 1 + 1 = 2
Fibonacci(4) = Fibonacci(3) + Fibonacci(2) = 2 + 1 = 3
Fibonacci(5) = Fibonacci(4) + Fibonacci(3) = 3 + 2 =
algoritmo Fibona(n)
Si ((n = 0) v (n = 1)) Entonces
Retornar n
sino
Retornar Fibona(n-1) + Fibona(n-2)
fSi
fMetodo
Fibonacci
anlisis
Sea T(1) para el control del bucle.
Sea de un tiempo T(n-1) para la primera llamada recursiva
Sea de un tiempo T(n-2) para la segunda llamada
recursiva
Entonces: T(n) = 1 + T(n-1) + T(n-2)
Tomando n-1 en vez de n: T(n-1) = 1 + T(n-2) + T(n-3)
Tomando n-2 en vez de n: T(n-2) = 1 + T(n-3) + T(n-4)
Por tanto en el ltimo ciclo : T(2) = 1 + T(1) + T(0)
algoritmo Fibona(n)
Si ((n = 0) v (n = 1)) Entonces
Retornar n
sino
Retornar Fibona(n-1) + Fibona(n-2)
fSi
fMetodo
Fibonacci
anlisis
algoritmo Fibona(n)
Si ((n = 0) v (n = 1)) Entonces
Retornar n
sino
Retornar Fibona(n-1) + Fibona(n-2)
fSi
fMetodo

T(n) = (n-1) + T(n-2) + T(n-3) + T(n-4) + . + T(1) + T(0)
T(n) = n + {T(n-2) + T(n-3) + T(n-4) + . + T(1) }
T(n) = n + n*T(n) = n + n
2

Por tanto O(n
2
)
Sumando a ambos lados de las
ecuaciones se tiene:
PASO N PILA FIBONACI PROX
0 4 4
1 4 Fibo(2)+, 3
2 3 Fibo(2)+,Fibo(1)+, 2
3 2 Fibo(2)+,Fibo(1)+,Fibo(0)+, 1
4 1 Fibo(2)+,Fibo(1)+,Fibo(0)+, 1 2
5 2 Fibo(2)+,Fibo(1)+,Fibo(0)+, 1 0
6 0 Fibo(2)+,Fibo(1)+, 0 2
7 2 Fibo(2)+,Fibo(1)+, 1(1+0) 3
8 3 Fibo(2)+,Fibo(1)+, 1 1
9 1 Fibo(2)+, 1 3
10 3 Fibo(2)+, 2(1+1) 4
11 4 Fibo(2)+, 2 2
12 2 Fibo(0)+, 1
13 1 Fibo(0)+, 1 2
14 2 Fibo(0)+, 1 0
15 0 0 2
16 2 1(1+0) 4
17 4 3(2+1)
Funcionamiento Interno de la
Recursin
Calculo recursivo del
Fibonacci(n=4)
39
El problema de Torres de Hanoi
Tenemos 3 torres y N discos de diferentes
tamaos; cada uno con una perforacin en el
centro que le permite deslizarse por las
torres.

Inicialmente los N discos estn ordenados de
mayor a menor en la primera de las torres.

Se debe pasar los discos a otra torre en el
mismo orden, utilizando la tercera torre como
auxiliar.

En cada movimiento slo se puede mover un
disco y no puede quedar uno de mayor
tamao sobre uno menor tamao.
A
A B C B
C
A: Origen
B: Destino
C:Auxiliar
El problema de Torres de Hanoi
algoritmo hanoi (n, A, B, C)
si (n = 1) entonces
escribir(mover disco de A a B)
sino
hanoi(n-1, A, C, B)
escribir(mover disco de A a B)
hanoi( n-1, C, B, A)
finhanoi
A
A B C B
C
A: Origen
B: Destino
C:Auxiliar
41
El problema de Torres de Hanoi
Concluimos que rbol recursivo nos
permite calcular en funcin del # de
hojas, cuantas llamadas recursivas se
dan: 2
n
- 1

rbol recursivo de Torres de Hanoi
para n = 3
H(3,1,2,3)
H(2,3,2,1)
H(1,1,2,1)
H(2,1,3,2)
H(1,1,2,3)
H(1,3,1,2)
H(1,2,3,1)
1-2
2-3
2-3 1-2
3-1
3-2
1-2
42
Conclusiones
Divide y vencers es adecuado para
reducir un problema a varios casos ms
pequeos de si mismo

La recursin es adecuada para la solucin
que consiste en hacer sucesivas llamadas
a si mismo.

Estos mtodos deben tener una regla de
detencin que indique que el problema est
terminado.

Estos mtodos no da mayor rapidez, ni
ahorra espacio de memoria; pero el cdigo
es mas compacto y en ciertos casos ms
fcil de aprender.
LABORATORIO

Realice los siguiente programas de forma recursiva usando la
tcnica dyv e implemntelo en java o C++.


1. Se tiene un arreglo A de enteros, de tamao N>0, con nmeros enteros
positivos y negativos. Realice un algoritmo DyV que encuentre el menor
nmero entero que se encuentre en este arreglo y retorne su posicin, en
caso no existir retorne -1. Muestre su analisis.


2. Se tiene un arreglo A de enteros, de tamao N>0, ordenado
ascendentemente. Realice un algoritmo DyV que encuentre un ndice i
talque: 1<= i <= N y A[i]= i, si existe elemento retorne i, de contrario
retorne -1. Muestre su analisis.

Vous aimerez peut-être aussi