Está en la página 1de 8

Grado en Ingeniería Informática

Metodología de la programación

Metodología de la
programación.

Trabajo de programación dinámica.

Grupo A.1 Boris Fajardo Peral


Martín Cambronero Honrubia
Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 1
Grado en Ingeniería Informática
Metodología de la programación

Programación dinámica.

Existen una serie de problemas cuyas soluciones pueden ser expresadas


recursivamente en términos matemáticos, y posiblemente la manera más natural de
resolverlos es mediante un algoritmo recursivo. Sin embargo, el tiempo de ejecución
de la solución recursiva puede mejorarse substancialmente mediante la Programación
Dinámica.

Dicha programación no sólo tiene sentido aplicarla por razones de eficiencia, sino
porque presenta un método capaz de resolver problemas cuya solución ha sido
abordado por otras técnicas y ha fracasado.

Donde tiene mayor aplicación es en la resolución de problemas de optimización ya


que en este tipo de problemas se suelen encontrar distintas soluciones y lo que se
desea es encontrar la solución de valor óptimo.

La solución de problemas mediante esta técnica se basa en el llamado principio de


óptimo enunciado por Bellman en 1957 y que dice:

“En una secuencia de decisiones óptima toda subsecuencia ha de ser también óptima”.

Pongamos un ejemplo para explicar el enunciado de Bellman:

Queremos que un viajante realice un viaje de Madrid a Barcelona, si encontramos el


camino óptimo del viaje tenemos que el camino desde cualquier punto del recorrido
hasta el punto inicial (Madrid) y al hasta el punto final (Barcelona) es Óptimo.

Para que un problema pueda ser resuelto con esta técnica, debe cumplir con ciertas
características:

 El problema se puede dividir en etapas.


 Cada etapa tiene un número de estados asociados a ella.
 La decisión óptima de cada etapa depende solo del estado actual y no de las
decisiones anteriores.
 La decisión tomada en una etapa determina cual será el estado de la etapa
siguiente.

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 2


Grado en Ingeniería Informática
Metodología de la programación

El diseño de un algoritmo de programación dinámica consta de aproximadamente los


siguientes pasos:

1. Planteamiento de la solución como una sucesión de decisiones y verificación


de que ésta cumple el principio de óptimo.
2. Definición recursiva de la solución.
3. Cálculo del valor de la solución óptima mediante una tabla en donde se
almacenan soluciones a problemas parciales para reutilizar los cálculos.
4. Construcción de la solución óptima haciendo uso de la información contenida
en la tabla anterior.

Problema.
Se denomina filotaxis a la disposición que presentan las hojas en el tallo. La
disposición que presentan es característica de cada especie y tiene la función de que
las hojas estén expuestas al sol con el mínimo de interferencias posibles por parte de
sus compañeras.

A lo largo de los años, los científicos han comprobado que existe una relación directa
entre la filotaxis y los números de la sucesión de Fibonacci. Contando las espiras
según la trayectoria de hojas, escamas (piñas) o estambres (girasoles), se tiene que el
número de espiras en ambos sentidos nunca es el mismo y siempre coinciden con
números consecutivos de la sucesión de Fibonacci.

Se pretende diseñar un algoritmo para determinar, en función de este principio, si un


vegetal pertenece o no al mundo real, dando el número de espiras como parámetro.

El algoritmo consiste en generar números según la sucesión de Fibonacci, haciendo


las comprobaciones oportunas para determinar si pertenece o no. Siendo Fib[i] un
array de enteros, n y m el número de espirales en cada sentido ordenado tal que n<m

1 𝑠𝑖 𝑖 = 0 ∨ 𝑖 = 1
𝐹𝑖𝑏(𝑖) =
Fib(i − 1) + Fib(i − 2) en otro caso

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 3


Grado en Ingeniería Informática
Metodología de la programación

Si Fib[i] > n && Fib[i-1]<n n no pertenece a la sucesión, devuelvo 0.


Fin Si

Si (Fib[i] >= m) && (Fib[i]>m || Fib[i-1] != n) m no pertenece a la sucesión || m y n


no son consecutivos, devuelvo 0.
Else devuelvo 1.

Como puede verse, el algoritmo se basa en una tabla de resultados (unidimensional).


Se tiene una sucesión de etapas. Cada etapa tiene un estado asociado. A partir de este
estado se toma una decisión que afectará o no al siguiente estado. Se evita la
recursividad, que produciría cálculos innecesarios.

Ejemplo 1:
Tenemos la sospecha de que Nickelodeon intenta engañar a nuestros hermanos
haciéndoles creer que Bob Esponja vive en una piña debajo del mar. Haciendo uso de
nuestro algoritmo, vamos a demostrar matemáticamente que, aun que una piña
pudiera vivir en el fondo del mar, eso no es una piña.

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 4


Grado en Ingeniería Informática
Metodología de la programación

Como podemos ver claramente, se forman 5 espiras (líneas) en cada sentido. Si


introducimos estos valores en nuestro algoritmo:

El programa nos dice que esa piña no puede ser real, ya que el número de espiras, aun
que pertenece a la sucesión de Fibonacci, no es consecutivo.

Ejemplo 2:
Vamos a demostrar que nuestro algoritmo puede demostrar que el girasol de la
siguiente foto pertenece al mundo real.

Si nos dedicamos a contar las espiras del girasol llegamos a la conclusión de que
tenemos 21 espiras en un sentido y 34 en el otro.

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 5


Grado en Ingeniería Informática
Metodología de la programación

Introduciendo dichos valores a nuestro algoritmo:

El programa determina que efectivamente, cumple la condición y por tanto no


tenemos evidencia de que no pertenezca al mundo real.

Análisis del coste computacional.


int fib(int n, int m){
int secuencia[MAX];
int i=1, aux;
secuencia[0]= 1;

if(n>m){ /* ordeno los valores, primero el menor */


aux=n; n=m, m=aux;
}

printf("\nSecuencia de Fibonacci: ");

/* Se genera la secuencia de Fibonacci*/


while(m > secuencia[i-1]){
if(i<=1)
secuencia[i]=1;
else
secuencia[i] = secuencia[i-1] + secuencia[i-2];

printf("%d ", secuencia[i]);

/* Si n no está en la secuencia, termino */


if(secuencia[i] > n && secuencia[i-1] < n)
return 0;

i++;
}

if(secuencia[i-1] > m) return 0; /* m != Fib[i] */


if(secuencia[i-2] != n) return 0; /* n no consecutivo */

return 1;
}

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 6


Grado en Ingeniería Informática
Metodología de la programación

El mayor coste viene dado por:

while(m>Fib[i]){
Fib[i] = Fib[i-1]+Fib[i-2];
i++;
}

La forma en la que “crece” Fib[i], partiendo de t(0)=1 y t(1)=1, viene dada por la
siguiente expresión:

t(n) = t(n-1)+t(n-2)

Que reescribiéndola es:

t(n)-t(n-1)-t(n-2)=0

El polinomio característico:

Cuyas raíces son:

Por lo que la solución general es de la forma:

Según las condiciones iniciales t(0)=1 y t(1)=1:

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 7


Grado en Ingeniería Informática
Metodología de la programación

Si resolvemos el sistema:

Sustituyendo en la ecuación general, tenemos:

𝑡(𝑛) = 1 · 1.6𝑛 ∈ 𝑂(1𝑛 )

Luego, el coste de nuestro algoritmo es de 𝑶(𝒍𝒐𝒈(𝒎))

Curso 2011/12 Boris Fajardo Peral & Martín Cambronero Honrubia 8

También podría gustarte