Está en la página 1de 146

TÉCNICA DE DISEÑO

DIVIDE Y CONQUISTA

Claudia Pereira - Liliana Martinez


Divide y conquista

Técnica de diseño de algoritmos resuelve un problema recursivamente,


aplicando tres pasos en cada nivel de la recursión:

• Divide el problema en un número de subproblemas que son instancias


menores del mismo problema.

• Conquista los subproblemas resolviéndolos recursivamente. Si el


tamaño del subproblema es suficientemente pequeño, lo resuelve de
manera directa.

• Combina las soluciones de los subproblemas para obtener la solución al


problema original.
Divide y Conquista
Divide y Conquista: Problemas

Características de los problemas

• El problema debe admitir una formulación recursiva.

• Los subproblemas deben ser del mismo tipo que el problema


original, pero con datos de tamaño estrictamente menor.

• El tamaño de los datos que manipulen los subproblemas ha de


ser lo más parecido posible.

Divide y Conquista
Divide y Conquista: Esquema algorítmico

DyC (P) { // P es el problema a resolver (de tamaño n)


if ( SIMPLE (P) ) // P pequeño -> su solución es directa
return Solucion_Directa (P);

else { // P es grande

DIVIDE P en k Subproblemas P1, P2,... Pk; // 1< k <=n


return ( COMBINA ( DyC(P1) , DyC(P2), ..., DyC(Pk) );
}
}

Divide y Conquista
Divide y Conquista: Análisis de Eficiencia
DyC (P) {
if ( SIMPLE (P) )
return Solucion_Directa (P);
else {
DIVIDE P en k Subproblemas P1, P2,... Pk;
return ( COMBINA ( DyC(P1) , DyC(P2), ..., DyC(Pk) );
}
}
Si el tamaño de P es n y el tamaño de los k subproblemas es n1, n2, ..., nk :

g(n) n pequeño
T(n) =
T(n1) + T(n2) + ... + T(nk) + f(n) n suficientemente grande

g(n) es el tiempo para resolver directamente las entradas pequeñas


T(n) es el tiempo de ejecución de DyC con n entradas,
f(n) es el tiempo de dividir P en subproblemas y combinar las soluciones.
Divide y Conquista
Divide y Conquista: Análisis de Eficiencia

• Nunca resuelve un problema más de una vez.

• Divide y Combina deben ser eficientes.

• El tamaño de los subproblemas debe ser lo más parecido posible.

• Si el subproblema es suficientemente pequeño


evitar generar nuevas llamadas recursivas

Divide y Conquista
MERGE-SORT

Divide y Conquista
MERGE-SORT
Merge-Sort es un método que aplica la técnica divide y conquista para
ordenar los elementos almacenados en un arreglo:

• Divide: divide el arreglo de n elementos en dos subarreglos de n/2


elementos cada uno.

• Conquista: Ordena los 2 subarreglos llamando recursivamente al


Merge-Sort.

• Combina: Combina las dos subsecuencias ordenadas para producir la


respuesta ordenada.

Divide y Conquista
MERGE-SORT
MERGE-SORT (A, i, d) {
// ordena los elementos del arreglo A[i...d]
if ( i < d )
// Si hay más de un elemento divide el problema de ordenar A
// en dos subproblemas
{ m ← ⌊(i + d)/2⌋
MERGE-SORT (A, i, m)
// llama recursivamente para ordenar A[i...m] ( ⌈n/2⌉ elementos)
MERGE-SORT (A, m + 1, d)
// llama recursivamente para ordenar A[m+1...d] ( ⌊n/2⌋ elementos)
MERGE (A, i, m, d) // combina los subarreglos para
// formar un único subarreglo ordenado A[i..d]
}
}

Divide y Conquista
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
MERGE (A, i, m, d)
}
}
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50

i m d
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50

1 2

A: 70 65
i,m d
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50

1 2

A: 70 65
i,m d
1

A: 70
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50

1 2

A: 70 65
i,m d
1 2

A: 70 A: 65
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50

1 2
MERGE asume que los subarreglos A[i..m] y A[m+1..d]
A: 70 65
están ordenados.
i,m d Luego, mezcla los elementos de los dos subarreglos para
1 2
MERGE formar un único subarreglo ordenado que reemplazará al
A: 70 A: 65 actual subarreglo A[i..d]
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50
i m d
1 2 3

A: 65 70 A: 50
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 70 65 50 MERGE asume que los subarreglos A[i..m] y A[m+1..d]


están ordenados.
i m d Luego, mezcla los elementos de los dos subarreglos para
1 2 MERGE 3
formar un único subarreglo ordenado que reemplazará al
A: 65 70 A: 50 actual subarreglo A[i..d]
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:

1 2 3

A: 50 65 70
i m d
1 2 MERGE 3

A: 65 70 A: 50
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3

A: 50 65 70
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 4 5

A: 50 65 70 A: 80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 4 5

A: 50 65 70 A: 80 85

80
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 4 5

A: 50 65 70 A: 80 85

4 5

80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 4 5

A: 50 65 70 A: 80 85

MERGE
4 5

80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 4 5

A: 50 65 70 A: 80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 70 65 50 80 85
} A:
i m d
1 2 3 MERGE 4 5

A: 50 65 70 A: 80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d) 1 2 3 4 5
} 50 65 70 80 85
} A:
i m d
1 2 3 MERGE 4 5

A: 50 65 70 A: 80 85
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
MERGE (A, i, m, d) 1 2 3 4 5
} 50 65 70 80 85
} A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5
} 50 65 70 80 85 60 55 75 45
} A: A:
i m d

… ...
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5
} 50 65 70 80 85 45 55 60 75
} A: A:
i m d
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 70 65 50 80 85 60 55 75 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45 50
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45 50 55
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45 50 55 60
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45 50 55 60 65 70 75 80 85
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d) i m d
6 7 8 9
MERGE (A, i, m, d) 1 2 3 4 5 MERGE
} 50 65 70 80 85 45 55 60 75
} A: A:

La función MERGE continúa hasta mezclar todos los elementos de


los dos subarreglos para formar un único subarreglo ordenado que
reemplazará al actual subarreglo A[i..d]
MERGE-SORT: ejemplo

MERGE-SORT (A, i, d) { 1 2 3 4 5 6 7 8 9
if ( i < d )
{ m ← ⌊(i + d)/2⌋ A: 45 50 55 60 65 70 75 80 85
MERGE-SORT (A, i, m)
MERGE-SORT (A, m + 1, d)
MERGE (A, i, m, d)
}
}

El arreglo A queda ordenado después de aplicar la función MERGE-SORT


MERGE-SORT: Complejidad temporal
Se asume que el tamaño del problema original es potencia de 2, lo cual no afecta
el orden de crecimiento de la solución de la recurrencia.
Si la cantidad de elementos del arreglo a ordenar, n, es potencia de 2, entonces,
cada paso Divide divide el arreglo original en dos subarreglos de exactamente n/2
elementos cada uno.

c0 n pequeño
T(n) =
2 T(n/2) + cn + c n suficientemente grande

El tiempo requerido por mergesort es proporcional a n log n.

Divide y Conquista
MERGE-SORT

Ventaja: el tiempo requerido por mergesort es proporcional a n log n.

Desventaja: requiere espacio adicional proporcional a n (para el


arreglo auxiliar de la función merge).

Divide y Conquista
QUICKSORT

Divide y Conquista
QUICKSORT
Quicksort es un método que aplica la técnica divide y conquista para ordenar
los elementos almacenados en un arreglo:

• Divide: Selecciona un elemento y particiona el arreglo en dos


subarreglos (posiblemente vacíos) A[i…p-1] y A[p+1.. d] tal que:
• El elemento seleccionado queda ordenado (en su posición final: p)
• los elementos en A[i…p-1] son menores o igual que A[p] y
• los elementos en A[p+1..d] son mayores que A[p]

• Conquista: Ordena los subarreglos A[i…p-1] y A[p+1.. d] llamando


recursivamente al quicksort

• Combina: No hay necesidad de combinar las soluciones (por la forma que


divide, ordena los subarreglos, luego todo el arreglo queda ordenado)

Ordena el arreglo sobre si mismo => no requiere almacenamiento adicional

Divide y Conquista
QUICKSORT
void QUICKSORT (Type A[], int i, int j) {

// ordena los elementos de A[i], A[i+1],..., A[j-1], A[j] ascendentemente

if (i < j) { // Si hay más de un elemento divide el problema de


// ordenar a en dos subproblemas

int p = PARTICION ( A, i, j ); // p es la posición del pivote


//resuelve los subproblemas
QUICKSORT (A, i, p-1);
QUICKSORT (A, p+1, j);
//No hay necesidad de combinar las soluciones.
}
}

Divide y Conquista
QUICKSORT : Partición
Primer paso: selecciona un pivote (por ejemplo, a[1])
1 2 3 4 5 6 7 8 9

a: 65 70 50 80 85 60 55 75 45

Pivote

Segundo paso: reordena los otros elementos de modo tal que:


• el pivote queda ordenado
• los elementos menores al pivote quedan a su izquierda
• los elementos mayores al pivote quedan a su derecha

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 70 50 80 85 60 55 75 45

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 70 50 80 85 60 55 75 45

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 80 85 60 55 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 85 60 80 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 85 60 80 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 85 60 80 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 85 60 80 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 60 85 80 75 70

i j
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 60 85 80 75 70

j i
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 60 85 80 75 70

j i
Pivote

Mientras i < j

Mientras a[i] ≤ pivote -> avanza i

Mientras a[j] > pivote -> retrocede j

intercambia a[i] con a[j] y avanza i y retrocede j

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

65 45 50 55 60 85 80 75 70

j i
Pivote

i > j =>

Intercambia el pivote con a[j]

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

60 45 50 55 65 85 80 75 70

Pivote

i > j =>

Intercambia el pivote con a[j]

Divide y Conquista
QUICKSORT : Partición

1 2 3 4 5 6 7 8 9

60 45 50 55 65 85 80 75 70

Pivote
elementos elementos
menores al pivote mayores al pivote

Divide y Conquista
QUICKSORT

1 2 3 4 5 6 7 8 9

60 45 50 55 65 85 80 75 70

Pivote
elementos elementos
menores al pivote mayores al pivote

Una vez realizada la partición, cada subarreglo es ordenado llamando recursivamente a quicksort

Divide y Conquista
QUICKSORT

1 2 3 4 5 6 7 8 9

45 50 55 60 65 70 75 80 85

Pivote
elementos elementos
menores al pivote mayores al pivote

Una vez ordenados los subarreglos, todo el arreglo está ordenado,

 No hace falta combinar.

Divide y Conquista
QUICKSORT
void QUICKSORT (Type A[], int i, int j) {

// ordena los elementos de A[i], A[i+1],..., A[j-1], A[j] ascendentemente

if (i < j) { // Si hay más de un elemento divide el problema de


// ordenar a en dos subproblemas

int p = PARTICION ( A, i, j ); // p es la posición del pivote


//resuelve los subproblemas
QUICKSORT (A, i, p-1);
QUICKSORT (A, p+1, j);
//No hay necesidad de combinar las soluciones.
}
}

Divide y Conquista
QUICKSORT: Complejidad temporal

El tiempo de ejecución depende de la partición:

partición balanceada el algoritmo corre asintóticamente tan


rápido como el ordenamiento
mergesort.

partición desbalanceada el algoritmo corre asintóticamente tan


lento como el ordenamiento por
inserción.

Divide y Conquista
QUICKSORT: Complejidad temporal

El peor caso ocurre cuando la partición produce:

un problema con 0 elementos un problema con n-1 elementos

p a [ i+1 … j ] > p
i j

un problema con n-1 elementos un problema con 0 elementos

a [ i … j-1] ≤ p p
i j

Divide y Conquista
QUICKSORT: Complejidad temporal

El peor caso: la partición desbalanceada ocurre en cada llamada recursiva =>

void QUICKSORT (Type A[], int i, int j)


{if (i < j)
c0 n ≤1 {
int p = PARTICION ( A, i, j );
T(n) QUICKSORT (A, i, p-1);
QUICKSORT (A, p+1, j);
T(n-1) + c1 n + c2 n>1 }
}

El tiempo de particionar  O (n)


El tiempo de llamar recursivamente sobre un arreglo de tamaño n-1 es T(n-1)
El tiempo de llamar recursivamente sobre un arreglo de tamaño 0  O(1)

Divide y Conquista
QUICKSORT: Complejidad temporal

El peor caso: la partición desbalanceada ocurre en cada llamada recursiva =>

void QUICKSORT (Type A[], int i, int j)


{if (i < j)
c0 n ≤1 {
int p = PARTICION ( A, i, j );
T(n) QUICKSORT (A, i, p-1);
QUICKSORT (A, p+1, j);
T(n-1) + c1 n + c2 n>1 }
}

T(n)  O ( n2)
El tiempo en el peor de los casos:
• No es mejor que el ordenamiento por inserción
• El peor tiempo ocurre cuando el arreglo ya está ordenado
Divide y Conquista
QUICKSORT: Complejidad temporal

El mejor caso ocurre cuando la partición produce:

un problema con n/2 elementos un problema con n/2 -1 elementos

a [ i … p-1 ] ≤ p p a [ p+1 … j ] > p


i j

Divide y Conquista
QUICKSORT: Complejidad temporal

El mejor caso: la partición balanceada ocurre en cada llamada recursiva =>

void QUICKSORT (Type A[], int i, int j)


c0 n ≤1 {if (i < j)
{
T(n) int p = PARTICION ( A, i, j );
QUICKSORT (A, i, p-1);
2 T(n/2) + c1 n + c2 n>1 QUICKSORT (A, p+1, j);
}
}
T(n)  O ( n log n)

El tiempo de llamar recursivamente sobre un arreglo de tamaño a lo sumo n/2


El tiempo de particionar  O (n)

Divide y Conquista
QUICKSORT: Complejidad temporal

El caso promedio es mucho más cercano al mejor caso que la peor caso.

El tiempo esperado es O (n log n)


Mejoras
• Si el peor caso se da cuando el arreglo está ordenado:
en lugar de seleccionar el primer elemento como pivote 
o elegir la mediana de algunos valores del arreglo (Ej: primero, medio y último)
o seleccionar un pivote al azar (Quicksort randomizado)

• cuando los subproblemas son pequeños (n=16) entonces usar un algoritmo de


ordenamiento iterativo simple como el de inserción

Divide y Conquista
QUICKSORT

Ejercicio:

Dado el siguiente arreglo particionar el arreglo


tomando el primer elemento del arreglo como pivote:

M I P R I M E R E J E M P L O

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Divide y Conquista
Problema del Torneo de Tenis

Divide y Conquista
Problema del Torneo de Tenis

Se debe organizar un torneo de tenis con n jugadores en donde:

 n es potencia de dos

 Cada jugador ha de jugar exactamente una vez contra cada uno de sus posibles
n–1 competidores,

 Cada jugador debe tener un encuentro diario, durante n-1 días.


Día 1 2 …
El programa del torneo es una tabla de Jugador
n filas por n-1 columnas 1
2
T[i,j] representa el jugador que debe 3
jugar con i el j-ésimo día ,,,

Divide y Conquista
Problema del Torneo de Tenis

La técnica D&C
Día 1
Jugador
• Si n = 2, caso base, sólo hay dos jugadores,
1 2
basta enfrentar uno contra el otro.
2 1
Día 1 2 3 4 5 6 7
Jugador
• Si n > 2, Divide y Conquista: la técnica construye un 1
2
programa para la mitad de los jugadores, aplicando
3

recursivamente el algoritmo, buscando un programa para la 4


5
mitad de esos jugadores, y así sucesivamente. 6
7
8

• Combina: A partir de la solución para la mitad de los jugadores, hemos


llenado el cuadrante superior izquierdo de la tabla, es fácil llenar los otros tres cuadrantes.

Divide y Conquista
Problema del Torneo de Tenis
Día 1 2 3 4 5 6 7
Ejemplo n= 8 Jugador

1
• Si n > 2: la técnica construye un programa para 2
la mitad de los jugadores 3
4
5
6
7
8

Divide y Conquista
Problema del Torneo de Tenis
Día 1 2 3 4 5 6 7
n= 4 Jugador

1
• Si n > 2: la técnica construye un programa para 2
la mitad de los jugadores 3
4
5
6
7
8

Divide y Conquista
Problema del Torneo de Tenis
Día 1 2 3 4 5 6 7
n= 2 Jugador

1 2
Caso Base: 2 jugadores  los enfrentamos
2 1
3
4
5
6
7
8

Divide y Conquista
Problema del Torneo de Tenis
Día 1 2 3 4 5 6 7
n= 4 Jugador

1 2 3 4
Una vez resuelto el caso base, retorna de la recursión
2 1 4 3
y procede a construir la solución:
3 4 1 2
1°) llena la mitad inferior izquierda: 4 3 2 1
enfrenta a los jugadores de numeración más alta 5
(suma n/2) a la solución obtenida para la numeración más baja. 6
7
2°) llena el cuadrante superior derecho:
8
El día n/2 se enfrenta a los jugadores de menor numeración
con los de mayor numeración y el resto de los días se permutan cíclicamente.

3°) llena el cuadrante inferior derecho:


Análogamente al cuadrante superior derecho, el día n/2 se enfrenta a los jugadores de mayor
numeración con los de menor numeración y el resto de los días se permutan cíclicamente, pero en
sentido contrario al cuadrante superior.
Divide y Conquista
Problema del Torneo de Tenis
Día 1 2 3 4 5 6 7
n= 8 Jugador

1 2 3 4 5 6 7 8
Llenó el primer cuadrante, retorna de la recursión
2 1 4 3 6 7 8 5
y procede a construir la solución:
3 4 1 2 7 8 5 6
1°) llena la mitad inferior izquierda: 4 3 2 1 8 5 6 7
enfrenta a los jugadores de numeración más alta 5 6 7 8 1 4 3 2
(suma n/2) a la solución obtenida para la numeración más baja. 6 5 8 7 2 1 4 3
7 8 5 6 3 2 1 4
2°) llena el cuadrante superior derecho:
El día n/2 se enfrenta a los jugadores de menor numeración 8 7 6 5 4 3 2 1
con los de mayor numeración y el resto de los días se permutan cíclicamente.

3°) llena el cuadrante inferior derecho:


Análogamente al cuadrante superior derecho, el día n/2 se enfrenta a los jugadores de mayor
numeración con los de menor numeración y el resto de los días se permutan cíclicamente, pero en
sentido contrario al cuadrante superior.
Divide y Conquista
Problema del Torneo de Tenis

Algoritmo:

Torneo ( Tabla, n)
{
if ( n == 2 ) // caso base
enfrentar a los dos jugadores
else
{ divide

Torneo (tabla, n/2);  conquista


llenar cuadrante inferior izq;
llenar cuadrante superior derecho; combina
llenar cuadrante inferior derecho;
}
}

Divide y Conquista
Problema del Torneo de Tenis

Complejidad Temporal
Torneo ( Tabla, n)
{
c0 , n = 2
if ( n == 2 ) // caso base
T(n)  enfrentar a los dos jugadores
T(n/2) + 3 (n/2)2 c1 + c2 , n > 2 else
{
Torneo (tabla, n/2);
llenar cuadrante inferior izq;
llenar cuadrante superior derecho;
T(n)  (n2) llenar cuadrante inferior derecho;
}
}

Divide y Conquista
Problema de la subsecuencia
de suma máxima

Divide y Conquista
Subsecuencia de suma máxima

Dada una secuencia de n enteros cualesquiera a1,a2,...,an, necesitamos encontrar


la subsecuencia que maximice la suma parcial de elementos consecutivos.

Por ejemplo:

1 -2 11 -4 13 -5 2 2

Subsecuencia de suma máxima  suma = 20

El problema es interesante sólo si el arreglo contiene números negativos.


Si los números fuesen positivos la solución sería el arreglo entero.
Divide y Conquista
Subsecuencia de suma máxima

Dada una secuencia de n enteros cualesquiera a1,a2,...,an, necesitamos encontrar


la subsecuencia que maximice la suma parcial de elementos consecutivos.

Por ejemplo:

1 -2 11 -4 13 -5 2 2

Subsecuencia de suma máxima  suma = 20

Un algoritmo ingenuo: chequea O(n2) subarreglos

Costoso!!!
Divide y Conquista
Subsecuencia de suma máxima

La técnica Divide y Conquista sugiere dividir el arreglo en 2


subarreglos de igual tamaño.

La subsecuencia de suma máxima (SSM) caerá en alguno de los


siguientes lugares:

primera mitad segunda mitad

cruza el punto medio

Divide y Conquista
Subsecuencia de suma máxima

La técnica Divide y Conquista sugiere dividir el arreglo en 2


subarreglos de igual tamaño y:

• Encontrar la SSM en la primer mitad y la SSM en la segunda


mitad recursivamente

(ya que estos 2 subproblemas son instancias menores del


problema de hallar la SSM)

• Encontrar la SSM que cruza el punto medio

• Devolver la subsecuencia de mayor suma de las tres.

Divide y Conquista
Subsecuencia de suma máxima
Algoritmo para resolver el problema de la SSM por divide y conquista:
bajo
Encontrar_SSM ( A, bajo, alto ) { alto
if (alto == bajo) // caso base: solo un elemento A
return < bajo, alto, A[bajo] >;
medio
else { // cálculo de subproblemas bajo alto
medio = (alto + bajo) / 2; A

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

// Subproblema: Parte derecha


<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);

Divide y Conquista
Subsecuencia de suma máxima
Encontrar_SSM ( A, bajo, alto ) {


// Combinar soluciones
<bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);

if ((sumaIzq > sumaDer ) and ( sumaIzq > sumaMedio))


return < bajoIzq, altoIzq, sumaIzq>;

else if ((sumaDer >= sumaIzq) and (sumaDer > = sumaMedio))


return < bajoDer, altoDer, sumaDer>;

else return < bajoMedio, altoMedio, sumaMedio> Retorna la subsecuencia


que suma más

Divide y Conquista
Subsecuencia de suma máxima

Veamos primero cómo encontrar la SSM que cruza el punto medio…

Este problema no es una instancia menor del problema original, ya que tiene la
restricción adicional que el subarreglo debe cruzar el punto medio.

SoluciónMedio ( A, bajo, medio, alto)

A 1 -2 11 -4 13 -5 2 2

bajo medio alto

Divide y Conquista
Subsecuencia de suma máxima

SoluciónMedio ( A, bajo, medio, alto) {


sumaIzq = -∞
suma = 0
for i = medio hasta bajo
suma += A[ i ]
if (suma > sumaIzq )
sumaIzq = suma
indiceIzq = i
sumaDer = -∞
suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma
indiceDer = j
return < indiceIzq, IndiceDer, sumaIzq + sumaDer >
} O(n)
Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0

sumaIzq = -∞
suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = - ∞ if (suma > sumaIzq )
sumaIzq = suma
indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4

Suma > sumaIzq sumaIzq = -∞


suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = - ∞ if (suma > sumaIzq )
sumaIzq = suma
indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4

Suma > sumaIzq sumaIzq = -∞


suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = - 4 if (suma > sumaIzq )
sumaIzq = suma
IndiceIzq = medio indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4
Suma + A[ 2 ] = -4 +11 = 7
sumaIzq = -∞
Suma > sumaIzq suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = - 4 if (suma > sumaIzq )
sumaIzq = suma
IndiceIzq = medio indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4
Suma + A[ 2 ] = -4 +11 = 7
sumaIzq = -∞
Suma > sumaIzq suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = 7 if (suma > sumaIzq )
sumaIzq = suma
IndiceIzq = 2 indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4
Suma + A[ 2 ] = -4 +11 = 7
sumaIzq = -∞
Suma + A[ 1 ] = -4 +11 - 2 = 5 suma = 0
for i = medio hasta bajo
suma += A[ i ]
SumaIzq = 7 if (suma > sumaIzq )
sumaIzq = suma
IndiceIzq = 2 indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio alto


i

Suma = 0
Suma + A[ medio ] = -4
Suma + A[ 2 ] = -4 +11 = 7
sumaIzq = -∞
Suma + A[ 1 ] = -4 +11 - 2 = 5 suma = 0
for i = medio hasta bajo
Suma + A[ 0 ] = -4 +11 - 2 + 1= 6 suma += A[ i ]
SumaIzq = 7 if (suma > sumaIzq )
sumaIzq = suma
IndiceIzq = 2 indiceIzq = i

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0

sumaDer = -∞
suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = - ∞
indiceDer = j

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0
Suma + A[ medio+1 ] = 13

sumaDer = -∞ Suma > sumaDer


suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = - ∞
indiceDer = j

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0
Suma + A[ medio+1 ] = 13

sumaDer = -∞ Suma > sumaDer


suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = 13
indiceDer = j IndiceDer = 4
Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0
Suma + A[ medio+1 ] = 13
Suma + A[ 5 ] = 13 – 5 = 8
sumaDer = -∞
suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = 13
indiceDer = j IndiceDer = 4
Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0
Suma + A[ medio+1 ] = 13
Suma + A[ 5 ] = 13 – 5 = 8
sumaDer = -∞ Suma + A[ 6 ] = 13 – 5 + 2= 10
suma = 0
for j = medio + 1 hasta alto
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = 13
indiceDer = j IndiceDer = 4
Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

bajo medio j alto

Suma = 0
Suma + A[ medio+1 ] = 13
Suma + A[ 5 ] = 13 – 5 = 8
sumaDer = -∞ Suma + A[ 6 ] = 13 – 5 + 2= 10
suma = 0
for j = medio + 1 hasta alto Suma + A[ 7 ] = 13 – 5 + 2 + 2 = 12
suma += A[ j ]
if (suma > sumaDer )
sumaDer = suma SumaDer = 13
indiceDer = j IndiceDer = 4
Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

SumaIzq = 7 SumaDer = 13
IndiceIzq = 2 IndiceDer = 4

Divide y Conquista
Subsecuencia de suma máxima
0 1 2 3 4 5 6 7

A 1 -2 11 -4 13 -5 2 2

IndiceIzq = 2 IndiceDer = 4
Suma = 20

SolucionMedio

return < IndiceIzq, IndiceDer, SumaIzq + SumaDer >

return < 2, 4, 7 + 13 >


Ir a final
Divide y Conquista
Subsecuencia de suma máxima
Teniendo el procedimiento para obtener la SSM que cruza el punto medio,
podemos resolver el problema de la SSM por divide y conquista:

Encontrar_SSM ( A, bajo, alto ) {


if (alto == bajo) // caso base
return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

// Subproblema: Parte derecha


<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);

Divide y Conquista
Subsecuencia de suma máxima
Encontrar_SSM ( A, bajo, alto ) {


// Combinar soluciones
<bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);

if ((sumaIzq > sumaDer ) and ( sumaIzq > sumaMedio))


return < bajoIzq, altoIzq, sumaIzq>;

else if ((sumaDer >= sumaIzq) and (sumaDer > = sumaMedio))


return < bajoDer, altoDer, sumaDer>;

else return < bajoMedio, altoMedio, sumaMedio>

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7

bajo alto

Encontrar_SSM ( A, bajo, alto ) {


if (alto = = bajo) // caso base
return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

// Subproblema: Parte derecha


<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7

medio=(alto+bajo)/2= 3

Encontrar_SSM ( A, bajo, alto ) {


if (alto = = bajo) // caso base
return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

Encontrar_SSM ( A, bajo, alto ) {


if (alto = = bajo) // caso base
return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
1 -2 return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;

// Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
1 -2 return < bajo, alto, A[bajo] >;
else // cálculo de subproblemas
medio { medio = (alto + bajo) / 2;

1 // Subproblema: Parte izquierda


<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio

1 -2

Encontrar_SSM ( A, bajo, alto ) {


if (alto = = bajo) // caso base
1
return < bajo, alto, A[bajo] >;
alto = bajo …
Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio

1 -2
< 0,0,1 >
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
1
return < bajo, alto, A[bajo] >;

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio
Encontrar_SSM ( A, bajo, alto ) {
if …
else // cálculo de subproblemas
1 -2 { medio = (alto + bajo) / 2;
< 0,0,1 > medio+1 // Subproblema: Parte izquierda
<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

// Subproblema: Parte derecha


<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio

1 -2
< 0,0,1 > medio+1
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
-2
return < bajo, alto, A[bajo] >;
alto = bajo …
Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio

1 -2
< 0,0,1 > < 1,1,-2 >
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
-2
return < bajo, alto, A[bajo] >;
alto = bajo …
Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio Encontrar_SSM ( A, bajo, alto ) {



// Subproblema: Parte izquierda
1 -2 …
< 0,0,1 > < 1,1,-2 > // Subproblema: Parte derecha

// Combinar soluciones
<bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);

…. Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4

medio Encontrar_SSM ( A, bajo, alto ) {


< 0,1,-1 > …
// Combinar soluciones
1 -2 <bajoMedio, altoMedio, sumaMedio> =
< 0,0,1 > < 1,1,-2 > SolucionMedio( A, bajo, medio, alto);

….

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio Encontrar_SSM ( A, bajo, alto ) {
< 0,1,-1 > …
// Combinar soluciones
1 -2 …
< 0,0,1 > < 1,1,-2 > If ((sumaIzq > sumaDer ) and ( sumaIzq > sumaMedio))
return < bajoIzq, altoIzq, sumaIzq>;
else If ((sumaDer >= sumaIzq) and (sumaDer > = sumaMedio))
return < bajoDer, altoDer, sumaDer>;
else return < bajoMedio, altoMedio, sumaMedio>

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio
Encontrar_SSM ( A, bajo, alto ) {
if …
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;
// Subproblema: Parte izquierda
<bajoIzq, altoIzq,sumaIzq> = Encontrar_SSM (A, bajo, medio);

// Subproblema: Parte derecha


<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);
Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo)
return < bajo, alto, A[bajo] >;
11 -4 else
{ medio = (alto + bajo) / 2;
medio
// Subproblema: Parte izquierda
<bajoIzq, altoIzq,sumaIzq> =
Encontrar_SSM (A, bajo, medio);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio

11 -4

medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
11 return < bajo, alto, A[bajo] >;
alto = bajo …

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio

11 -4
< 2,2,11 >
medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
11 return < bajo, alto, A[bajo] >;

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
Encontrar_SSM ( A, bajo, alto ) {
< 0,0,1 > medio if …
else // cálculo de subproblemas
{ medio = (alto + bajo) / 2;
// Subproblema: Parte izquierda
11 -4
< 2,2,11 > <bajoIzq, altoIzq,sumaIzq> =
Encontrar_SSM (A, bajo, medio);
medio
// Subproblema: Parte derecha
<bajoDer, altoDer,sumaDer> =
Encontrar_SSM (A, medio+1, alto);

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio

11 -4
< 2,2,11 >
medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
-4 return < bajo, alto, A[bajo] >;
alto = bajo …

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio

11 -4
< 2,2,11 > < 3,3,-4 >
medio
Encontrar_SSM ( A, bajo, alto ) {
if (alto = = bajo) // caso base
-4 return < bajo, alto, A[bajo] >;
alto = bajo …

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio Encontrar_SSM ( A, bajo, alto ) {

// Subproblema: Parte izquierda
11 -4
< 2,2,11 > < 3,3,-4 >
medio // Subproblema: Parte derecha

// Combinar soluciones
<bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);

…. Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio
Encontrar_SSM ( A, bajo, alto ) {
1 -2 11 -4 …

< 0,0,1 > // Combinar soluciones


medio <bajoMedio, altoMedio, sumaMedio> =
< 2,3,7 > SolucionMedio( A, bajo, medio, alto);

11 -4 ….
< 2,2,11 > < 3,3,-4 >
medio

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio

1 -2 11 -4
< 0,0,1 > medio < 2,2,11 >
< 2,3,7 > retorna la tripla con suma máxima

11 -4
< 2,2,11 > < 3,3,-4 >

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio
// Combinar soluciones
1 -2 11 -4 <bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);
< 0,0,1 > medio < 2,2,11 >

Suma = 0
Suma + A[ medio ] = -2

Suma + A[ 0 ] = -2 +1 = -1
SumaIzq = -1
IndiceIzq = 0

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio
// Combinar soluciones
1 -2 11 -4 <bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);
< 0,0,1 > medio < 2,2,11 >

Suma = 0
Suma + A[ medio+1 ] = 11

Suma + A[ 3 ] = 11-4 = 7
SumaDer = 11
IndiceDer = 2

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio
// Combinar soluciones
1 -2 11 -4 <bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);
< 0,0,1 > medio < 2,2,11 >

SumaIzq = -1 SumaDer = 11
IndiceIzq = 0 IndiceDer = 2

return < IndiceIzq, IndiceDer, sumaIzq + sumaDer > < 0, 2, 10 >

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
medio
< 0, 2, 10 >
// Combinar soluciones
1 -2 11 -4 <bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto);
< 0,0,1 > medio < 2,2,11 >

return < IndiceIzq, IndiceDer, sumaIzq + sumaDer > < 0, 2, 10 >

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2

< 2,2,11 > 0 1 2 3 4 5 6 7


medio
< 0, 2, 10 >

1 -2 11 -4 retorna la tripla con suma máxima

< 0,0,1 > < 2,2,11 >

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > medio

13 -5 2 2

resuelto el subproblema de la parte Izquierda, nos resta


resolver el subproblema de la parte Derecha

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > medio

13 -5 2 2

Encontrar_SSM ( A, bajo, alto ) {


// Subproblema: Parte izquierda



// Subproblema: Parte derecha
<bajoDer, altoDer,sumaDer> = Encontrar_SSM (A, medio+1, alto);

// Combinar Soluciones

Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > medio < 4,4,13 >
< 4,7,12 >
13 -5 2 2
< 4,4,13 > < 6,7,4 >
< 4,5,8 > < 6,7,4 >
13 -5 2 2
< 4,4,13 > < 5,5,-5 > < 6,6,2 > < 7,7,2 >

13 -5 2 2
< 4,4,13 > < 5,5,-5 > < 6,6,2 > < 7,7,2 >
Divide y Conquista
Subsecuencia de suma máxima

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > medio < 4,4,13 >

Encontrar_SSM ( A, bajo, alto ) {



// Combinar soluciones
<bajoMedio, altoMedio, sumaMedio> =
SolucionMedio( A, bajo, medio, alto); < 2,4,20 >
….

Ir a SolucionMedio

Divide y Conquista
Subsecuencia de suma máxima
< 2,4,20 >

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > medio < 4,4,13 >

Encontrar_SSM ( A, bajo, alto ) {



// Combinar soluciones
… SolucionMedio …

if ((sumaIzq > sumaDer ) and ( sumaIzq > sumaMedio))


return < bajoIzq, altoIzq, sumaIzq>;

else if ((sumaDer >= sumaIzq) and (sumaDer > = sumaMedio))


return < bajoDer, altoDer, sumaDer>;

else return < bajoMedio, altoMedio, sumaMedio>


Divide y Conquista
Subsecuencia de suma máxima
< 2,4,20 >

A 1 -2 11 -4 13 -5 2 2
0 1 2 3 4 5 6 7
< 2,2,11 > < 4,4,13 >

Subsecuencia de suma máxima  suma = 20

Divide y Conquista
Subsecuencia de suma máxima

Complejidad temporal:

• Algoritmo por fuerza bruta  O ( n2 )

• Algoritmo por Divide y Conquista

co n=1
T (n) =
2 T (n/2) + n c1 n>1

T SolucionMedio

Divide y Conquista
Subsecuencia de suma máxima

Complejidad temporal:

• Algoritmo por fuerza bruta  O ( n2 )

• Algoritmo por Divide y Conquista  O ( n log n )

co n=1
T (n) =
2 T (n/2) + n c1 n>1

T SolucionMedio

Divide y Conquista
Subsecuencia de suma máxima

Para pensar:
 Escriba un algoritmo no recursivo que en tiempo lineal resuelva el problema
de hallar la subsecuencia de suma máxima

Pistas:
Ninguna secuencia de suma máxima comienza o termina con un número negativo.
Recorrer el arreglo de izquierda a derecha, guardando el subarreglo máximo encontrado
hasta el momento.
Si conoce el subarreglo de suma máxima A[1..j], extienda la solución para encontrar un
subarreglo máximo que termina en j+1, usando la siguiente información:
Para algún 1 <= i <= j+1, un subarreglo máximo de A[1..j+1] es
• o un subarreglo máximo de A[1..j]
• o un subarreglo máximo de A[i…j+1]

Divide y Conquista
BIBLIOGRAFÍA

• Cormen, T.; Lieserson, C.; Rivest, R. Introduction to


Algorithms Ed. The MIT Press. 2009.

• Horowitz, E.; Sahni, S.; Rajasekaran, S. Computer


Algorithms. Computer Science Press.1998.

• Brassard, G.; Bratley, P. Prentice-Hall. Fundamentos de


Algoritmia. 1997.

También podría gustarte