Estrategias de programación

Divide y vencerás

Programación Dinámica

Divide y vencerás

  • Divide el problema en subproblemas que son instancias más pequeñas del mismo problema.
  • Vence los subproblemas resolviéndolos recursivamente.
  • Combina las soluciones de los subproblemas para obtener la solución del problema original.

Ejemplo: Ordenamiento por mezcla

template<typename T_>
void mergeSort(T_ arr[], int low, int high)
{
    if(low < high)
    {
        int mid = (low + high)/2;
        // Ordenar recursivamente 
        // las mitades del arreglo
        mergeSort(arr, low, mid);
        mergeSort(arr, mid + 1, high);
        // Mezclar las mitades del 
        // arreglo ordenadas
        merge(arr, low, mid, high);
    }
}
template<typename S_>
void merge(S_ arr[], int low, int mid, int high)
{
    S_ *b = new int[high - low + 1];
    int h = low;
    int i = 0;
    int j = mid +1;
    // Mezcla las dos mitades ordenadas en 
    // interaciones anteriores
    while(h <= mid && j <= high)
    {
        if(arr[h] <= arr[j])
        {
            b[i] = arr[h];
            ++h;
        }
        else
        {
            b[i] = arr[j];
            ++j;
        }
        ++i;
    }
    // Completa el arreglo con 
    // los valores restantes
    if(h > mid)
    {
        for(int k = j; k <= high; ++k)
        {
            b[i] = arr[k];
            ++i;
        }
    }
    else
    {
        for(int k = h; k <= mid; ++k)
        {
            b[i] = arr[k];
            ++i;
        }
    }
    // Mover la parte ordenada 
    // al arreglo original
    memcpy(arr + low, b, 
            (high - low + 1) * sizeof(S_));
    delete[] b;
}

Teorema maestro

  • Caso base: T(n) <= a para todo n lo suficientemente menor.
  • Para todo n mayor: T(n) <= aT(n/b) + O(n^d)

donde:

a = número de llamadas recursivas (>= 1)

b = el factor de reducción de los datos de entrada (> 1)

d = exponente del tiempo de ejecución en el paso de combinación (>= 0)

Entonces:

T(n) =

O(n^d log n)

O(n^d)

O(n^(log_b a))

Si a = b^d (caso 1)

Si a < b^d (caso 2)

Si a > b^d (caso 3)

Aplicación del teorema maestro: Mergesort

  • a = 2 se hacen 2 llamadas recursivas antes de combinar.
  • b = 2 se divide en subroblemas de n/2
  • d = 1 tiempo de ejecución O(n) al combinar. 

a = b^d (caso 1), entonces: T(n) = O(n log n)

Programación dinámica

Consiste en dividir el problema en subproblemas más pequeños y simples hasta llegar a un punto donde la solución del problema es trivial.

 

Se utiliza principalmente cuando en la resolución de los subproblemas recursivamente se pueden traslapar las soluciones.

Ejemplo: Dijkstra's shortest path algorithm 

Dado un conjunto de nodos, sus caminos y el costo de recorrer estos caminos, encontrar el camino más corto y con menos costo entre dos nodos.

Divide y vencerás - Programación dinámica

By Victor Romero

Divide y vencerás - Programación dinámica

  • 772