Análisis de algoritmos

Documentos relacionados
Análisis de algoritmos

Programación Dinámica

Análisis de algoritmos. Recursividad

Análisis de algoritmos

Estrategias de Diseño de Algoritmos

Tema 5- Diseño Recursivo y. Objetivos Principales. Bibliografía Básica

Programación Dinámica

Programación Dinámica

259. El número de combinaciones de m objetos entre un conjunto de n, denotado por n, para n 1 y 0 m n, se puede definir recursivamente por: m

Programación Dinámica 1

Ejemplo: El problema de la mochila. Algoritmos golosos. Algoritmos y Estructuras de Datos III. Segundo cuatrimestre 2013

Universidad de Valladolid. Departamento de informática. Campus de Segovia. Estructura de datos Tema 1: Recursividad. Prof. Montserrat Serrano Montero

Algoritmos. Diseño de algoritmos por inducción. Alberto Valderruten. Dept. de Computación, Universidade da Coruña

4.2. El número de combinaciones de m objetos entre un conjunto de n, denotado por n, para n 1 y 0 m n, se puede definir recursivamente por: m

Estructuras de Datos y de la Información Ingeniería Técnica en Informática de Gestión. Curso 2007/2008 Ejercicios del Tema 2

Tema 9. Recursividad

Tema 10: Árbol binario de búsqueda

UNIVERSIDAD DE LOS ANDES NUCLEO UNIVERSITARIO RAFAEL RANGEL (NURR) DEPARTAMENTO DE FISICA Y MATEMATICA AREA COMPUTACION TRUJILLO EDO.

La recursividad forma parte del repertorio para resolver problemas en Computación y es de los métodos más poderosos y usados.

Algoritmos glotones. mat-151

Técnicas de diseño de algoritmos Programación dinámica

Tema 02: Algoritmia y pseudocódigo

Jueves, 30 de abril. Ejemplo de recursión. Ejemplo de PD. Ejemplo de programación dinámica. Programación dinámica

Análisis de algoritmos

Programación I Recursividad.

1. PRINCIPIOS BÁSICOS DE PROGRAMACIÓN

Tema: Funciones, Procedimientos y Recursividad en C#.

Algoritmos: Diseño de algoritmos por inducción

UAA Sistemas Electrónicos Estructura de Datos Muñoz / Serna

AMBIENTE INTERACTIVO PARA LA VISUALIZACIÓN DE CONCEPTOS ASOCIADOS A LAS TÉCNICAS DE DISEÑO DE ALGORITMOS

Taller de Programación Dinámica. Definiciones. Caso base. Laboratorio de Algoritmos y Estructuras de Datos III. 10 de Septiembre de 2010

Tema 7: Recursividad

Tema: Funciones, Procedimientos y Recursividad en C#.

Multiplicación de matrices simétricas

La segunda observación permite reformular el problema de una manera más simple:

Programación Estructurada

Recursión. Capítulo 4

Esquema de Dividir y Vencer

TEMA 5: Subprogramas, programación modular

Análisis de algoritmos

Programación dinámica: un último ejemplo

Análisis y Diseño de Algoritmos

Tema 2. Divide y vencerás.

FICHA DE TRABAJO Nº 14

2.1 METODOLOGÍA PARA LA SOLUCIÓN DE PROBLEMAS

Introducción a la Programación Dinámica. El Problema de la Mochila

Subrutinas. Subrutinas. Erwin Meza Vega

Controla el flujo de tokens reconocidos por parte del analizador léxico. 4.2 Introduccion a las gramaticas libres de contexto y arboles de derivacion

Programación dinámica p. 1

RECURRENCIA RECURSIÓN o RECURSIVIDAD

Recursión Directa. Una función es de recursión directa si contiene una llamada explícita a si misma. return foo (y 1); Recursión Indirecta

Tema 2 Conceptos básicos de programación. Fundamentos de Informática

Introducción a la programación en C eme - Escuela Universitaria de Música

El determinante de una matriz se escribe como. Para una matriz, el valor se calcula como:

Tema 13: Apuntadores en C

Álgebra Lineal Ma1010

Algorítmica y Complejidad. Tema 5 Divide y Vencerás.

Matemáticas Discretas Enrique Muñoz de Cote INAOE. Permutaciones y Combinaciones

Si un número es múltiplo de otro, u dicho de forma, comprobar si un número es divisor de otro.

Tema 01: Algoritmia y diagramas de flujo. Estructuras de datos (Prof. Edgardo A. Franco)

Problemas de programación entera: El método Ramifica y Acota. Investigación Operativa, Grado en Estadística y Empresa, 2011/12

Figura 1: Esquema de las tablas simplex de inicio y general.

Algoritmos y solución de problemas. Fundamentos de Programación Otoño 2008 Mtro. Luis Eduardo Pérez Bernal

INTRODUCCIÓN AL USO DE PAQUETES COMPUTACIONALES

UNIVERSIDAD NACIONAL DE SAN ANTONIO ABAD DEL CUSCO

TEMA 1: Algoritmos y programas

CAPÍTULO 6 PROGRAMACIÓN DINÁMICA. Programación Dinámica

Tema 4: Procedimientos y estructuras recursivas

Tema 5: Traducción dirigida por la sintaxis

UNIDAD DE APRENDIZAJE I

TÉCNICO UNIVERSITARIO EN COMPUTACIÓN E INFORMÁTICA GUÍA DE ESTUDIO ANÁLISIS Y DISEÑO DE ALGORITMOS I CÓDIGO Elaborada por Kay Guillén Díaz

Ejercicios sobre recursividad

Complejidad computacional (Análisis de Algoritmos)

Alineamiento múltiple de secuencias

Razonamiento Combinatorio (Combinaciones Sin Repetición

SGUICES029MT22-A17V1. Bloque 22 Guía: Teorema de Thales y división de segmentos

Algoritmos y programas. Algoritmos y Estructuras de Datos I

Exponencial, lineal y logarítmico

MATEMÁTICAS APLICADAS A LAS CCSS II (2º BACHILLERATO)

Introducción. Algoritmos y Complejidad. Algoritmos y Algoritmia. Introducción. Problemas e instancias. Pablo R. Fillottrani

PROGRAMACIÓN DINÁMICA. Idalia Flores

Cubiertas convexas II

MATEMÁTICAS APLICADAS A LAS CIENCIAS SOCIALES II DISTRITO ÚNICO DE ANDALUCÍA

Computación I Curso Facultad de Ingeniería Universidad de la República

Métodos de gradiente. Métodos de Krylov

Reflexiones adicionales

Unidad 2: Ecuaciones, inecuaciones y sistemas.

PROGRAMA DE MATEMÁTICA NÚCLEO COMÚN - SEGUNDO DE BACHILLERATO REFORMULACIÓN AJUSTE 2010 INTRODUCCIÓN

Modelos de Desarrollo de Programas Y Programación Concurrente Clase N 3

Fundamentos de Programación. Flujo de Control I: Estructuras selectivas

ALN - Curso 2007 Gradiente Conjugado

Programación MODULAR: Subalgoritmos - funciones y procedimientos

Programación I. Ingeniería Técnica Informática. Ejercicios de los Temas 4, 5, 6 y 7

Una Introducción a la Programación Estructurada en C

CRITERIOS DE EVALUACIÓN DEPARTAMENTO DE MATEMÁTICAS

EJERCICIOS RESUELTOS DE COMBINATORIA

Para las ecuaciones diferenciales ordinarias no lineales no existen métodos generales.

Diagramas. En computación existen básicamente dos tipos de diagramas: diagramas de entradaproceso salida

Lenguajes y Compiladores Análisis Sintáctico Parte I. Teoría Lenguajes 1

Propiedades de números enteros (lista de problemas para examen)

Transcripción:

Tema 09: Programación dinámica M. en C. Edgardo Adrián Franco Martínez http://www.eafranco.com edfrancom@ipn.mx @edfrancom edgardoadrianfrancom 1

Contenido Introducción Programación dinámica Enfoques de la programación dinámica Principio de optimalidad Diseño de un algoritmo de programación dinámica Ejemplos Fibonacci Cálculo del coeficiente binomial 2

Introducción La técnica divide y vencerás señala que es posible dividir un problema en subproblemas y combinar las soluciones para resolver el problema original. En ocasiones resolver subproblemas nos lleva a considerar subproblemas idénticos. Si aprovechamos la duplicación, resolviendo cada problema una sola vez, guardando la solución para su uso posterior entonces tendremos un algoritmo más eficiente. 3

La idea de la programación dinámica es evitar repetición de cálculos. La base de la programación dinámica es el razonamiento inductivo: Como resolver un problema combinando soluciones para problemas más pequeños? Se resuelven primero los subproblemas más pequeños y por tanto más simples. Combinando las soluciones se obtienen las soluciones de ejemplares sucesivamente más grandes hasta llegar al ejemplar original. 4

Programación dinámica La programación dinámica es un método para reducir el tiempo de ejecución de un algoritmo mediante la utilización de subproblemas superpuestos y subestructuras óptimas. Una subestructura óptima significa que se pueden usar soluciones óptimas de subproblemas para encontrar la solución óptima del problema en su conjunto. Un problema tiene subproblemas superpuestos si se usa un mismo subproblema para resolver diferentes problemas mayores. 5

Los algoritmos divide y vencerás están dentro de los métodos descendentes. Empezar con el problema original y descomponerlo en pasos sucesivos en problemas de menor tamaño. La programación dinámica por el contrario, es un método ascendente: Resolver primero los problemas pequeños (guardando las soluciones) y después combinarlas para resolver problemas más grandes. La programación dinámica hace uso de: Subproblemas superpuestos Subestructuras óptimas Memoizacion 6

En general, se pueden resolver problemas con subestructuras óptimas siguiendo estos tres pasos: 1. Dividir el problema en subproblemas más pequeños. 2. Resolver estos problemas de manera óptima usando este proceso de tres pasos recursivamente. 3. Usar estas soluciones óptimas para construir una solución óptima al problema original. Los subproblemas se resuelven a su vez dividiéndolos en subproblemas más pequeños hasta que se alcance el caso fácil, donde la solución al problema es trivial. 7

Ejemplo: Fibonacci (Problemas Ο(c n ) 8

Si se llama a fib(5), se produce un árbol de llamadas que contendrá funciones con los mismos parámetros varias veces: 1. fib(5) 2. fib(4) + fib(3) 3. (fib(3) + fib(2)) + (fib(2) + fib(1)) 4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1)) 5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1)) 9

Cuando se llega en el árbol a los casos base (señalados en la imagen) evidentemente las llamadas a la función se detienen. Pero también podemos notar que existen varios casos en donde se llama recursivamente a números que ya fueron calculados, por ejemplo el 3. Entonces para subsecuentes llamadas la cantidad de operaciones a calcular se volverían exponenciales y la complejidad aproximada sería O(c n ) lo cuál para un n=20 ya es mucho que calcular (O( 1+ 5 2 )n 15,127 llamadas a la función). 10

Originalmente, el término de programación dinámica se refería a la resolución de ciertos problemas y operaciones fuera del ámbito de la Ingeniería Informática, al igual que hacía la programación lineal. Aquel contexto no tiene relación con la programación en absoluto; el nombre es una coincidencia. El término también lo usó en los años 40 Richard Bellman, un matemático norteamericano, para describir el proceso de resolución de problemas donde hace falta calcular la mejor solución consecutivamente. Algunos lenguajes de programación funcionales, sobre todo Haskell, pueden usar la memorización automáticamente sobre funciones con un conjunto concreto de argumentos, para acelerar su proceso de evaluación. Esto sólo es posible en funciones que no tengan efectos secundarios. 11

Memoizacion Los subproblemas superpuestos provocan resolver varias veces el mismo problema, ya que la solución de un subproblema requiere calcular soluciones que otro subproblema también tenga que calcular. Perder tiempo calculando varias veces la solución al mismo subproblema se puede evitar guardando las soluciones que ya hemos calculado. Entonces, si necesitamos resolver el mismo problema más tarde, podemos obtener la solución de la lista de soluciones calculadas y reutilizarla. Este acercamiento al problema se llama memoización (Memoization en inglés) o memorización se diferencia de 'memorización' puesto que el término ya era usado en matemáticas). 12

Se puede resolver el problema, utilizando el enfoque de memorización (guardar los valores que ya han sido calculados para utilizarlos posteriormente). Así, rellenaríamos una tabla con los resultados de los distintos subproblemas, para reutilizarlos cuando haga falta en lugar de volver a calcularlos. La tabla resultante sería una tabla unidimensional con los resultados desde 0 hasta n. 13

En programación dinámica comúnmente se utilizan tablas de resultados conocidos que se va generando a medida que se resuelven los subcasos. Function Fibonacci (n:int): int; if (n=0) return 0; else if (n=1) return 1; else if (Fib[n]!=NONE) return Fib[n]; else Fib[n]=Fibonacci(n-1)+fibonacci(n-2); return Fib[n]; f(4) f(3) f(2) f(2) f(1) f(1) f(0) f(1) f(0) 14 f(4) f(3) f(2) f(1) f(0)

Subestructuras óptimas Donde tiene mayor aplicación la Programación Dinámica es en la resolución de problemas de optimización. En este tipo de problemas se pueden presentar distintas soluciones, cada una con un valor, y lo que se desea es encontrar la solución de valor óptimo (máximo o mínimo). 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. 15

Enfoques de la programación dinámica Top-down: El problema se divide en subproblemas, y estos se resuelven recordando las soluciones por si fueran necesarias nuevamente. Es una combinación de memoización y recursión. Bottom-up: Todos los problemas que puedan ser necesarios se resuelven de antemano y después se usan para resolver las soluciones a problemas mayores. Este enfoque es ligeramente mejor en consumo de espacio y llamadas a funciones, pero a veces resulta poco intuitivo encontrar todos los subproblemas necesarios para resolver un problema dado. 16

Fibonacci utilizando (Programación dinámica -Top-down) int tabla[n]; // tabla {-1,-1,,-1} int fibonacci(int n) { if (n<2) return n; if(tabla[n-1] == -1) tabla[n-1] = fibonacci(n-1); if(tabla[n-2] == -1) tabla[n-2] = fibonacci(n-2); tabla[n] = tabla[n-1] + tabla[n-2]; return tabla[n]; } Ο(n) 17

Fibonacci utilizando (Programación dinámica - Buttom-up) int fibonacci(int n) { int i; if (n<2) { return n; } else { tabla[0] = 0; tabla[1] = 1; for(i = 2; i < n; i++) tabla[i] = tabla[i-1] + tabla[i-2]; } return tabla[n-1]; } Ο(n) 18

Principio de optimalidad Cuando hablamos de optimizar nos referimos a buscar alguna de las mejores soluciones (solución optima) de entre muchas alternativas posibles. Dicho proceso de optimización puede ser visto como una secuencia de decisiones que nos proporcionan la solución optima. En este caso sigue siendo posible el ir tomando decisiones elementales, en la confianza de que la combinación de ellas seguirá siendo óptima, pero será entonces necesario explorar muchas secuencias de decisiones para dar con la correcta, siendo aquí donde interviene la programación dinámica. 19

En una secuencia de decisiones óptima toda subsecuencia ha de ser también óptima Contemplar un problema como una secuencia de decisiones equivale a dividirlo en problemas más pequeños y por lo tanto más fáciles de resolver como hacemos en Divide y Vencerás. La programación dinámica se aplica cuando la subdivisión de un problema conduce a: Una enorme cantidad de problemas. Problemas cuyas soluciones parciales se solapan. Grupos de problemas de muy distinta complejidad. 20

Diseño de un algoritmo de programación dinámica Para que un problema pueda ser abordado por esta técnica ha de cumplir dos condiciones: 1. La solución al problema ha de ser alcanzada a través de una secuencia de decisiones, una en cada etapa. 2. Dicha secuencia de decisiones ha de cumplir el principio de optimalizad. 21

El diseño de un algoritmo de Programación Dinámica consta de 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* o iterativa de la solución. 3. Cálculo del valor de la solución óptima mediante una estructura de datos 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 estructura de datos. 22

Cálculo del coeficiente binomial Los coeficientes binomiales o números combinatorios son una serie de números estudiados en combinatoria que indican el número de formas en que se pueden extraer subconjuntos a partir de un conjunto dado. P.g. Se tiene un conjunto con 6 objetos diferentes {A,B,C,D,E,F}, de los cuales se desea escoger 2 (sin importar el orden de elección). Cuántas formas de elección existen? A B C D E F A,B A,C A,D A,E A,F B,C B,D B,E B,F C,D C,E C,F D,E D,F E,F 23

El número de formas de escoger k elementos a partir de un conjunto de n, puede denotarse de varias formas: C n, k, n C k, C 6,2 = 6 C 2 = 6 2 = 15 Los números C(n,k) se conocen como coeficientes binomiales, pero es frecuente referirse a ellos como combinaciones de n en k, o simplemente n en k. n El coeficiente binomial es el número de subconjuntos k de k elementos escogidos de un conjunto con n elementos n k El coeficiente binomial n k está dado por la fórmula n k = n! k! n k! 24

Forma recursiva del coeficiente binomial n k = 1 n 1 k 1 + n 1 k 0 si k = 0 o k = n si 0 < k < n en caso contrario Si se desea calcular C(5,3), Cuáles son los casos que se repiten? funcion C(n,k) { Si k = 0 o k = n entonces devolver 1 sino si 0 < k< n devolver C(n-1,k-1) + C(n-1,k) sino devolver 0 } 25

Coeficiente binomial (Top-down) int tabla[n] [n]; // tabla[][] {-1,-1,,-1} int coef_bino (int n) { if (k==0 k==n) return 1; else if(k>0&&k<n) { if(tabla[n-1][k-1]==-1) tabla[n-1][k-1]=coef_bino(n-1,k-1); if(tabla[n-1][k]==-1) tabla[n-1][k]=coef_bino(n-1,k); return tabla[n-1][k-1]+tabla[n-1][k]; } else return 0; } 26

El algoritmo recursivo que los calcula resulta ser de complejidad exponencial por la repetición de los cálculos que realiza. No obstante, es posible diseñar un algoritmo con un tiempo de ejecución de orden O(nk) basado en la idea del Triángulo de Pascal. Para ello es necesario la creación de una tabla bidimensional en la que ir almacenando los valores intermedios que se utilizan posteriormente. 27

Coeficiente binomial (Bottom-up) Se ira construyendo la tabla por filas de arriba hacia abajo y de izquierda a derecha mediante el siguiente algoritmo de complejidad polinómica (Bottom-up). int coef_bino(int n, int k) { int i, j; for(i = 0; i <= n; i++) tabla[i][0] = 1; } for(i = 1; i<= n; i++) tabla[i][1] = i; for(i = 2; i<= k; i++) tabla[i][i] = 1; for(i = 3; i <= n; i++) for(j = 2; j <= i-1; j++) if(j <= k) tabla[i][j] = tabla[i-1][j-1] + tabla[i-1][j]; return tabla[n][k]; 28

Resultado Triangulo de Pascal 29