Está en la página 1de 15

Análisis y Diseño de Algoritmos

Divide y Vencerás
Cesar Liza Avila

website : www.cesarliza.com
e-mail : creadores@hotmail.com

César Liza Avila www.cesarliza.com


Divide y Vencerás
Esquema general

1) Descomponer un problema en subproblemas más pequeños del mismo


tipo con lo cual la recursión es una técnica adecuada.
2) Resolver cada subproblema.
3) Combinar los resultados para construir la solución al problema original.

Inicio
Si el problema es pequeño
resolverlo
Sino
descomponer en subproblemas
para cada subproblema
resolverlo
combinarlos
Fin

Cuando el subproblemas es solo de un tamaño una unidad menor se llama


simplificación o reducción.

César Liza Avila www.cesarliza.com


Análisis de la complejidad de funciones DyV

Ciertamente el análisis de la complejidad de funciones recursivas


es más complejo, debiendo utilizar las llamadas funciones de
recurrencia, las cuales deben ser resueltas.

Sin embargo, las funciones DyV (divide y vencerás) que


parte el problema en varios problemas mas pequeños y
del mismo tipo se pueden resolver fácilmente aplicando
el llamado Teorema Maestro.

César Liza Avila www.cesarliza.com


Teorema Maestro
Donde:
a>=1
Θ(1), si n<=no b>1
T(n) k>=0
aT(n/b) + Θ(nk), si n > no no>=0

Si el tamaño del problema es pequeño (n<=no), entonces se puede resolver


en tiempo constante.

Si el tamaño del problema es grande (n>no), entonces dividimos el problema


en a subproblemas de tamaño n/b.

El valor de a es el número de veces en que se llaman recursivamente, y n/b


es el tamaño de la entrada en cada llamada.

El término Θ(nk), especifica la cantidad de tiempo requerida para realizar la


descomposición, así como el tiempo requerido para combinarlas.

Θ(nk) si a<bk
Θ(nk log n ) si a=bk
Θ(nlog ba) si a>bk
César Liza Avila www.cesarliza.com
Ejemplo: Potencia entera de un número

Escriba un programa para elevar un número a


una potencia entera, esto es:

Xn

César Liza Avila www.cesarliza.com


# include <iostream.h>
int pot(int, int); Código
void main(void)
{
int b, e;
cout<<"Base: "; cin>>b;
cout<<“Exponente: "; cin>>e;

cout<<pot(b, e)<<endl;
}
int pot (int b, int e)
{
if (e==0) return 1;
if (e==1) return b; ¿usa “divide y vencerás” la
if (e==2) return b*b; siguiente función?

int p=pot(b, e/2); int pot2(int b, int e)


if (e % 2 == 0) {
return p*p; if (e==0) return 1;
else if (e==1) return b;
return p*p*b; return b*pot2(b,e-1);
} }
César Liza Avila www.cesarliza.com
Cálculo de la complejidad
La función pot( ), divide el problema en un subproblema de la mitad del
tamaño (T(n/2) ), y en el peor de los casos la condicional efectuará 2
multiplicaciones (esto ocurre cuando e es impar).

1, si n=1 Θ(1), si n<=no


T(n) Comparando con T(n)
T(n/2) + 2, si n>1 aT(n/b) + Θ(nk), si n > no

Por el teorema maestro


Tenemos:
a=1
Θ(nk) si a>bk
b=2 Θ(nk log n ) si a=bk 
k=0 (ya que 2 es constante) Θ(nlog ba) si a<bk

De donde la complejidad de pot( ) es Θ(log n)


César Liza Avila www.cesarliza.com
Ejemplo: Subsecuencia de suma máxima

El problema del subsecuencia de suma máxima consiste en encontrar un


secuencia cuya suma sea máxima dentro de un vector original.

-1 6 -2 5 -1 4 3 -4 3 1

La suma máxima se consigue desde los subíndices 1 al 6 y es 15

César Liza Avila www.cesarliza.com


Solución mediante divide y vencerás (DyV)
Dividimos el arreglo en dos partes.

La subsecuencia máxima puede estar en la primera mitad


(lo resolvemos por recursión)

La subsecuencia máxima puede estar en la segunda mitad


(lo resolvemos por recursión)

La subsecuencia máxima puede empezar en la primera


mitad y terminar en la segunda
(lo resolvemos calculando la subsecuencia máxima de
la primera mitad pero que termine en el ultimo elemento
de esa mitad y…
… calculando la subsecuencia máxima de la segunda
mitad pero que empiece en el ultimo elemento de esa
mitad…
…las dos se unen para construir la subsecuencia de
suma máxima).
Esto significa que hemos dividido el problema original en
3 subproblemas más pequeños.
César Liza Avila www.cesarliza.com
Código int sumDerBorde = 0;
int maxSumDerBorde = 0;
# include <iostream.h>
for ( int j=centro+1; j<=der; j++ )
int sumaMax(int [], int, int);
{
sumDerBorde += a[j];
void main(void)
if ( sumDerBorde > maxSumDerBorde )
{
maxSumDerBorde = sumDerBorde;
int a[]={-1, 6, -2, 5, -1, 4, 3, -4, 3, 1};
}
cout<<"la suma es:" << sumaMax(a, 0, 9)<<endl;
}
// calcula la mayor suma entre maxSumIzq,
int sumaMax(int a[ ], int izq, int der) // maxSumDer y la maxima suma que empieza
{ // en una mitad y termina en otra
if ( izq==der ) int max =maxSumIzq;
return a[izq]>0? a[izq]:0; if( maxSumDer > max)
max=maxSumDer;
int centro=(izq+der)/2; if( maxSumIzqBorde + maxSumDerBorde > max)
// maxima suma de la 1ra mitad max= maxSumIzqBorde+ maxSumDerBorde;
int maxSumIzq = sumaMax(a, izq, centro);
// maxima suma de la 2da mitad return max;
int maxSumDer = sumaMax(a, centro+1, der); }
// maxima suma que empieza en una mitad y
termina en la otra
int sumIzqBorde = 0;
int maxSumIzqBorde= 0;
for(int i=centro; i>=izq; i--)
{
sumIzqBorde += a[i];
if ( sumIzqBorde > maxSumIzqBorde ) desde los subíndices 1 al 6
maxSumIzqBorde = sumIzqBorde; (modifique el prog para mostrarlo)
}
César Liza Avila www.cesarliza.com
Cálculo de la complejidad
La función sumaMax( ), se hace 2 llamadas recursivas de la mitad de tamaño,
y dos bucles que depende de n. Por lo que su recurrencia seria:

Θ(1), si n=1 Θ(1), si n<=no


Comparando con
T(n) T(n)
2.T(n/2) + Θ(n), si n>1 aT(n/b) + Θ(nk), si n > no

Por el teorema maestro


Tenemos:
a=2
Θ(nk) si a<bk
b=2 Θ(nk log n ) si a=bk 
k=1 Θ(nlog ba) si a>bk

De donde la complejidad de sumaMax( ) es Θ(nlog n)


César Liza Avila www.cesarliza.com
Ejemplo: Calendario de un campeonato
Se tiene que programar los encuentros de un campeonato que tiene n
participantes con la condición de que cada participante se enfrente a
cada uno de los otros solo una vez.

Para simplificar el problema suponga que n es una potencia de 2.

1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
2 1 4 3 6 7 8 5
3 4 1 2 7 8 5 6
4 3 2 1 8 5 6 7
5 6 7 8 1 4 3 2
6 5 8 7 2 1 4 3
7 8 5 6 3 2 1 4
8 7 6 5 4 3 2 1

César Liza Avila www.cesarliza.com


void torneo(int n, int tabla[][COL])
Código { int i, j;
if(n==2)
{ tabla[0][0]=2;
# include <iostream.h> tabla[1][0]=1;
# include <iomanip.h> }
# define COL 64 else
{ // llena el cuadrante superior izquierdo
torneo(n/2, tabla);
void torneo(int n, int tabla[][COL]); // llena el cuadrante inferior izquierdo
for (i=n/2; i<n; i++)
void main(void) for(j=0; j<n/2-1; j++)
{ tabla[i][j]=tabla[i-n/2][j] + n/2;
int n, tabla[COL][COL]; // llena el cuadrante superior derecho
for(i=0; i<n/2; i++)
cout<<"Nro de participantes (potencia de 2):"; for(j=n/2-1; j<n-1; j++)
cin>>n; if(i+j<n-1)
tabla[i][j]= i + j + 2;
torneo(n, tabla); else
tabla[i][j]= i + j - n/2 + 2;
for(int i=0; i<n; i++) // llena el cuadrante inferior derecho
{ for(i=n/2; i<n; i++)
for(int j=0; j<n-1; j++) for(j=n/2-1; j<n-1; j++)
if(i>j)
cout<<setw(3)<<tabla[i][j];
tabla[i][j] = i - j;
cout<<endl; else
} tabla[i][j] = i + n/2 - j;
} }
}
César Liza Avila www.cesarliza.com
Cálculo de la complejidad
La función torneo( ), divide el problema en un problema de la mitad de
tamaño y 3 partes más para completar la matriz.

Como ocurre una llamada recursiva, y como cada una de las 3 partes tiene
una complejidad cuadrática, tendremos:

2, si n=2 Θ(1), si n<=no


T(n) Comparando con T(n)
1.T(n/2) + 3n2, si n>=2 aT(n/b) + Θ(nk), si n > no

Tenemos: Por el teorema maestro


a=1 Θ(nk) si a<bk 
b=2
k=2 Θ(nk log n ) si a=bk
Θ(nlog ba) si a>bk

De donde la complejidad de torneo( ) es Θ(n2)


César Liza Avila www.cesarliza.com
César Liza Avila www.cesarliza.com

También podría gustarte