Professional Documents
Culture Documents
La programación dinámica es una técnica que permite la optimización de código, evitando realizar
cálculos que previamente han sido realizados. Generalmente, esta técnica utiliza una tabla de
resultados que se van llevando a cabo en la medida que se van resolviendo los subproblemas.
Para (Guerequeta & Vallecillo, 2000), la técnica dinámica tiene sentido aplicarla, porque a través de
ella es posible resolver problemas de forma eficiente, en comparación con otras técnicas de
programación. Se debe mencionar que no siempre, la programación dinámica tiene ordenes de
complejidad inferiores con relación a otras técnicas de programación.
Para (Jain et al., 2018), las siguientes son las dos propiedades principales de un problema que
sugieren que el problema se puede resolver usando la programación dinámica: subproblemas
superpuestos (Overlapping Subproblems) y subestructura óptima (Optimal Substructure). De lo
anterior se puede afirmar que la programación dinámica no es útil cuando no hay subproblemas
comunes (superpuestos) porque no tiene sentido almacenar las soluciones si no se necesitan de
nuevo. Por ejemplo, la búsqueda binaria no tiene subproblemas comunes (Jain et al., 2018).
El factorial de un valor positivo n, corresponde al producto de todos los números enteros positivos
desde 1 hasta n. La operación de factorial, tiene aplicación en diferentes áreas de las como la
simulación y la teoría combinatoria. La expresión n!, representa la notación matemática de factorial.
La función factorial se puede representar así: n! = 1 x 2 x 3 x … (n-1) x n
La expresión anterior, se puede expresar mediante el producto: n! = ∏𝑛𝑘=1 𝑘. La tabla 34 muestra los
primeros productos de la operación factorial.
N 0 1 2 3 4 5 6 7 8 9 10 11
n! 1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800
Con base en la anterior relación de recurrencia, el factorial para 3, se puede calcular así:
En el contexto de la programación dinámica existe dos estrategias para almacenar valores que se
pueden reutilizar: Memorización (Top Down) y Tabulación ((Bottom Up). Mediante la estrategia de
tabulación, la tabla se construye de abajo hacia arriba y devuelve la última entrada de la tabla. En
cada posición se va almacenando el correspondiente valor.
n 0 1 2 3 4 5 6 7 8 9 10 11
n! 0 1 1 2 3 5 8 13 21 34 55 89
Un ejemplo muy utilizado en esta sucesión, está relacionado con la secuencia en la reproducción de
conejos. Este ejemplo ha sido previamente presentado en (Cardona, Jaramillo, & Triviño, 2011). Con
base en la literatura, se puede afirmar que la reproducción de conejos sigue las siguientes reglas:
a) Cada pareja de conejos fértiles tiene una pareja de conejitos cada mes.
b) Cada pareja de conejos comienza a ser fértil a partir del segundo mes de vida.
c) Ninguna pareja de conejos muere ni deja de reproducirse (Bohórquez, 2006).
La tabla 36 muestra la cantidad conejos que debe haber al cabo de 6 meses
Mes 0 1 2 3 4 5
Cantidad de conejos 1 1 2 3 5 8
Se inicia con una pareja de conejos (mes 0). Esta pareja (A), al inicio del mes dos se reproduce con
lo cual quedaría la pareja de padres y la pareja de hijos (B). Al tercer mes la pareja B aun no es fértil
pues solo tiene un mes de vida, pero sus padres continuación siendo fértiles dando lugar a una nueva
pareja (C). Es decir, en el mes tres ya se tendrían 3 parejas. En el mes cuatro, la pareja A tiene un
nuevo hijo (D), al igual que la pareja B, mientras que la pareja C aun no es fértil pues solo tiene un
mes de vida, con lo cual quedaría cinco parejas. Esta relación de recurrencia se expresa de la
siguiente forma:
fib (0) = 1
fib (1) = 1
fib(n)= fib (n-1) + fib (n-2)
La figura 13, muestra cómo se van almacenando los valores anteriores, mediante la programación
dinámica.
Para mostrar una situación en la cual se deben conservar resultados parciales en un arreglo
bidimensional, se estudia el problema de los coeficientes binomiales. Los coeficientes binomiales o
combinaciones, indican combinaciones en las que se pueden extraer subconjuntos a partir de un
conjunto dado. Los números combinatorios satisfacen la siguiente propiedad:
Esta fórmula recursiva, permite calcular los números combinatorios sin multiplicar ni dividir, mediante
un procedimiento visual conocido hoy en día como “Triángulo de Pascal” de la figura 14, el cual se
puede representar mediante la combinatoria de los valores n y k.
C(1,1)= C(0,0)+C(0,1) = 1
La implementación del algoritmo recursivo, puede resultar de un orden de complejidad exponencial,
dada la cantidad de llamados a la función recursiva. El algoritmo recursivo, tiene un orden de
complejidad O(2n). El caso inductivo para esta implementación es: T(n) = b+2T(n-1), por lo tanto, es
de orden exponencial.
También es posible implementar un algoritmo con un orden de complejidad O(n 2), Para ello, es
posible apoyarse en una matriz o arreglo bidimensional en la que se van almacenando valores
intermedios. En la tabla 37, se presenta la tabla, por filas de arriba hacia abajo y de izquierda a
derecha. La tabla 37 se fundamenta de (Guerequeta & Vallecillo, 2000)
Tabla 4. Representación del triángulo de pascal
}
}
}
return matriz [n][k];
}
𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜 (0, 𝑛) = 𝑛 + 1, 𝑠𝑖 𝑚 = 0
𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜(𝑚, 𝑛) = { 𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜 (𝑚, 0) = 𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜 (𝑚 − 1, 1), 𝑠𝑖 𝑚 > 0
𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜(𝑚, 𝑛) = 𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜(𝑚 − 1, 𝑀𝑖𝑠𝑡𝑒𝑟𝑖𝑜(𝑚, 𝑛 − 1)), 𝑠𝑖 𝑚, 𝑛 > 0
m\n 0 1 2 3 4 n
0 1 2 3 4 5 n+1
1 2 3 4 5 6 n+2
2 3 5 7 9 11 2n + 3
3 5 13 29 61 125
A(3,265536-
4 13 65533 A(3,A(4,3))
3)
(n + 3 términos)
Cuando el parámetro m, llegue a cero, el algoritmo retorna directamente el valor resultado de n+1.
Para el condicional if(m>0 && n==0), se observa que existe una llamada recursiva en la cual solo
se modifica el primer parámetro y el parámetro n, queda convertido en un valor constante 1. En caso
contrario, en la función ackerman(m-1,ackerman(m,n-1)) , se observa que el segundo
parámetro invoca a sí mismo una llamada recursiva, y por tanto, el crecimiento de la función se puede
expresar de la siguiente manera.
…𝑚
22
2
Cuando el primer argumento sea 0, el resultado es b+1 y se va guardando. Mientras más resultados
estén almacenados en la matriz, menos cálculos realizará el método. Inicialmente, la matriz se
encuentra vacía, el programa aplicará recursividad para realizar los cálculos. En caso contrario, el
programa utilizará la recursividad para realizar los cálculos correspondientes.
El algoritmo de Floyd, se aplica en la teoría de grafos y permite encontrar los caminos más cortos en
un grafo, en el cual las aristas tienen un valor en la distancia entre los nodos. El algoritmo permite
encontrar el camino más corto entre los pares de vértices, sin entrar en detalles de los caminos. Para
usar el algoritmo, es necesario que el grafo sea dirigido y ponderado.
El algoritmo de Floyd permite estimar el menor camino entre los vértices de un grafo. Esa estimación
parte de una matriz de adyacencia que representa la estructura interna del grado. El cálculo genera
como resultante una matriz que contiene la distancia del camino que une pares de vértices. Para el
algoritmo de Floyd es posible establecer la siguiente relación de recurrencia y con la cual se estima
el camino mínimo, la cual es propuesta por (Guerequeta & Vallecillo, 2000) .
El uso de una matriz permite hacer caso omiso a repetir cálculos. Es por eso que, en la
implementación, se declara una matriz auxiliar, la cual almacena un valor entero que determina la
longitud del camino mínimo de cada par de vértices. La matrizAux toma para cada posición toma
el valor mínimo entre la matrizAux [i][j] y la suma de matrizAux [i][k] y matrizAux [k][j]. La
siguiente es una posible implementación del algoritmo de Floyd.
Es un algoritmo que tiene como propósito calcular el camino mínimo entre los vértices de un grafo
ponderado. La esencia del algoritmo se fundamenta en analizar cada uno de los caminos que salen
de un vértice y que llegan a otro determinado vértice. Ese análisis determina ese camino más corto
desde un vértice hasta todos los vértices que hacen parte del grafo. A continuación, se presenta una
implementación del algoritmo.
public void AlgoritmoDijkstra()
{
float menor;
for (int i=0;i<(n-1);i++)
{
S[i+1]=false;
D[i]=L[0][i+1];
}
S[0]=true;
for (int i=0;i<(n-2);i++)
{
menor= Menor();
S[pos]=true;
for (int j=0;j<(n-1);j++)
{
if (!S[j+1])
{
D[j]=Math.min(D[j],D[pos-1]+L[pos][j+1]);
}
}
}
}