Programación Dinámica

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

Análisis de algoritmos

Complejidad computacional (Análisis de Algoritmos)

Programación Dinámica 1

Algoritmos glotones. mat-151

Ecuaciones Diofánticas

Análisis de Algoritmos

Profesorado de Nivel Medio y Superior en Biología Matemática - 1º Cuatrimestre Año 2013 FUNCIÓN CUADRÁTICA

Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos

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

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

Algoritmos y programas. Algoritmos y Estructuras de Datos I

1. (F, +) es un grupo abeliano, denominado el grupo aditivo del campo.

Colegio Universitario Boston

Programación dinámica p. 1

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

Estatutos de Control C# Estatutos de Decisión (Selección)

MatemáticaDiscreta&Lógica 1

Ecuaciones Lineales en Dos Variables

Representación de números enteros: el convenio exceso Z

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

INSTITUCIÓN EDUCATIVA GABRIEL TRUJILLO CORREGIMIENTO DE CAIMALITO, PEREIRA

Problema - Sumando Digitos

Grafos. AMD Grado en Ingeniería Informática. AMD Grado en Ingeniería Informática (UM) Grafos 1 / 30

Notación Asintótica 2

3 Polinomios y funciones racionales

SESIÓN N 07 III UNIDAD RELACIONES Y FUNCIONES

Algoritmos para determinar Caminos Mínimos en Grafos

Métodos que devuelven valor Dado el siguiente triángulo rectángulo:

Parciales Matemática CBC Parciales Resueltos - Exapuni.

<tipo> Tipo de dato de los elementos del vector

Sistemas de ecuaciones lineales

Clases e instancias. Algoritmos y Estructuras de Datos I. Clases e instancias. memoria dinámica.

Problemas de Recursividad

Árboles Filogenéticos. BT7412, CC5702 Bioinformática Diego Arroyuelo. 2 de noviembre de 2010

OPTIMIZACIÓN VECTORIAL

Matrices Invertibles y Elementos de Álgebra Matricial

Lección 11: Ecuaciones lineales con dos incógnitas

Retículos y Álgebras de Boole

Lección 5: Ecuaciones con números naturales

Definición de Memoria

DIAGRAMAS DE FLUJOS. Qué son Los Diagramas de Flujo y Para qué se Usan?

TEMA 1. MATRICES, DETERMINANTES Y APLICACIÓN DE LOS DETERMINANTES. CONCEPTO DE MATRIZ. LA MATRIZ COMO EXPRESIÓN DE TABLAS Y GRAFOS.

Percentil q (p q ) Si en este conjunto de valores se quiere encontrar el percentil 20, la solución gráfica es muy simple

Este método se basa en buscar el elemento menor el vector y colocarlo en la primera

El Juego como Problema de Búsqueda

DISTRIBUCIÓN N BINOMIAL

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

GUIA INFORMATIVA DE RAZONES TRIGONOMÉTRICAS

Ámbito Científico-Tecnológico Módulo IV Bloque 2 Unidad 1 Tan real como la vida misma

Espacios Vectoriales. AMD Grado en Ingeniería Informática. AMD Grado en Ingeniería Informática (UM) Espacios Vectoriales 1 / 21

Tema 3. Análisis de costes

Lección 1: Números reales

Complejidad de los Algoritmos

Tema 2.- Formas Cuadráticas.

El Algoritmo E-M. José Antonio Camarena Ibarrola

Función lineal Ecuación de la recta

lasmatemáticas.eu Pedro Castro Ortega materiales de matemáticas

Tema 2: Teorema de estructura de los grupos abelianos finitamente generados.

Ecuaciones de primer grado o lineales

Tablas de dispersión (hash tables)

Unidad II. 2.1 Concepto de variable, función, dominio, condominio y recorrido de una función.

FUNDAMENTOS DEL ÁLGEBRA. Folleto De Trabajo Para La Clase ECUACIONES LINEALES EN DOS VARIABLES

Universidad de Santiago de Chile Facultad de Ciencia Departamento de Matemática y Ciencias de la Computación

funciones printf scanf

Algebra lineal y conjuntos convexos

DEPARTAMENTO DE MATEMATICAS Y FISICA Matemáticas Discreta

Formulación del problema de la ruta más corta en programación lineal


Derivadas Parciales (parte 2)

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

TEST DE RAZONAMIENTO NUMÉRICO. Consejos generales

RESOLUCIÓN DE SISTEMAS MEDIANTE DETERMINANTES

Aritmética de Enteros

MATEMATICA GRADO 9 II PERIODO PROF. LIC. ESP. BLANCA NIEVES CASTILLO R. CORREO: cel

NOTACIÓN O GRANDE. El análisis de algoritmos estima el consumo de recursos de un algoritmo.

UNIDAD 2. Logaritmos DEFINICION DE LOGARITMO. Definiciones:

SISTEMAS DE NUMERACION

sobre un intervalo si para todo de se tiene que. Teorema 1 Sean y dos primitivas de la función en. Entonces,

Alonso Ramírez Manzanares Computación y Algoritmos 10.03

En una recta numérica el punto que representa el cero recibe el nombre de origen.

Materia: Matemática de Tercer Año Tema: Pendiente

Métodos para escribir algoritmos: Diagramas de Flujo y pseudocódigo

ESTADÍSTICA DESCRIPTIVA

Tema: Excel Formulas, Funciones y Macros

REPASO DE Nºs REALES y RADICALES

Funciones Tipos de funciones y Recursividad

Programación NO Lineal (PNL) Optimización sin restricciones

Tema 13: Distribuciones de probabilidad. Estadística

Diagramas de secuencia

Programación. Tema 8: Tablas Hash. Apuntes elaborados por: Eduardo Quevedo, Aaron Asencio y Raquel López Revisado por: Javier Miranda el????

JUNIO Opción A

OPTIMIZACIÓN Y SIMULACIÓN PARA LA EMPRESA. Tema 4 Optimización no Lineal

Sistemas de ecuaciones lineales dependientes de un parámetro

Conjuntos y matrices. Sistemas de ecuaciones lineales

Universidad Nacional de Ingeniería Facultad de Ciencias. Física Computacional CC063. Algebra Lineal. Prof: J. Solano 2012-I

SISTEMAS DE ECUACIONES LINEALES Y MATRICES Dos ecuaciones lineales con dos

Cálculo I (Grado en Ingeniería Informática) Problemas adicionales resueltos

Representación de números enteros: el convenio complemento a uno

Transcripción:

Programación Dinámica Agustín Santiago Gutiérrez, Juan Cruz Piñero Facultad de Ciencias Exactas y Naturales - Universidad de Buenos Aires Facultad de Informática - Universidad Nacional del Comahue Training Camp 2017 Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 1 / 61

Contenidos 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 2 / 61

Contenidos Programación Dinámica Recursión 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 3 / 61

Programación Dinámica Sucesión de Fibonacci Recursión Sucesión de Fibonacci La sucesión de Fibonacci se define como f 0 = 1, f 1 = 1 y f n+2 = f n + f n+1 para todo n 0 Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 4 / 61

Programación Dinámica Sucesión de Fibonacci Recursión Sucesión de Fibonacci La sucesión de Fibonacci se define como f 0 = 1, f 1 = 1 y f n+2 = f n + f n+1 para todo n 0 Cómo podemos computar el término 100 de la sucesión de Fibonacci? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 4 / 61

Programación Dinámica Sucesión de Fibonacci Recursión Sucesión de Fibonacci La sucesión de Fibonacci se define como f 0 = 1, f 1 = 1 y f n+2 = f n + f n+1 para todo n 0 Cómo podemos computar el término 100 de la sucesión de Fibonacci? Cómo podemos hacerlo eficientemente? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 4 / 61

Programación Dinámica Algoritmos recursivos Recursión Definición Un algoritmo se dice recursivo si calcula instancias de un problema en función de otras instancias del mismo problema hasta llegar a un caso base, que suele ser una instancia pequeña del problema, cuya respuesta generalmente está dada en el algoritmo y no es necesario calcularla. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 5 / 61

Programación Dinámica Algoritmos recursivos Recursión Definición Un algoritmo se dice recursivo si calcula instancias de un problema en función de otras instancias del mismo problema hasta llegar a un caso base, que suele ser una instancia pequeña del problema, cuya respuesta generalmente está dada en el algoritmo y no es necesario calcularla. Ejemplo Para calcular el factorial de un número, un posible algoritmo es calcular Factorial(n) como Factorial(n 1) n si n 1 o 1 si n = 0 Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 5 / 61

Programación Dinámica Algoritmos recursivos Recursión Definición Un algoritmo se dice recursivo si calcula instancias de un problema en función de otras instancias del mismo problema hasta llegar a un caso base, que suele ser una instancia pequeña del problema, cuya respuesta generalmente está dada en el algoritmo y no es necesario calcularla. Ejemplo Para calcular el factorial de un número, un posible algoritmo es calcular Factorial(n) como Factorial(n 1) n si n 1 o 1 si n = 0 Veamos como calcular el n-ésimo fibonacci con un algoritmo recursivo Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 5 / 61

Programación Dinámica Recursión Cálculo Recursivo de Fibonacci 1 int fibo( int n) 2 { 3 i f (n<=1) 4 return 1; 5 else 6 return fibo(n 2)+fibo(n 1); 7 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 6 / 61

Programación Dinámica Recursión Cálculo Recursivo de Fibonacci 1 int fibo( int n) 2 { 3 i f (n<=1) 4 return 1; 5 else 6 return fibo(n 2)+fibo(n 1); 7 } Notemos que fibo(n) llama a fibo(n 2), pero después vuelve a llamar a fibo(n 2) para calcular fibo(n 1), y a medida que va decreciendo el parámetro que toma fibo son más las veces que se llama a la función fibo con ese parámetro. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 6 / 61

Programación Dinámica Problemas de la recursión Recursión La función que usamos para calcular Fibonacci tiene un problema. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 7 / 61

Programación Dinámica Problemas de la recursión Recursión La función que usamos para calcular Fibonacci tiene un problema. Llamamos muchas veces a la misma función con los mismos parámetros Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 7 / 61

Programación Dinámica Problemas de la recursión Recursión La función que usamos para calcular Fibonacci tiene un problema. Llamamos muchas veces a la misma función con los mismos parámetros Básicamente tenemos problemas de memoria. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 7 / 61

Programación Dinámica Problemas de la recursión Recursión La función que usamos para calcular Fibonacci tiene un problema. Llamamos muchas veces a la misma función con los mismos parámetros Básicamente tenemos problemas de memoria. Podemos solucionar esto? Podemos hacer que la función sea llamada pocas veces para cada parámetro? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 7 / 61

Programación Dinámica Problemas de la recursión Recursión La función que usamos para calcular Fibonacci tiene un problema. Llamamos muchas veces a la misma función con los mismos parámetros Básicamente tenemos problemas de memoria. Podemos solucionar esto? Podemos hacer que la función sea llamada pocas veces para cada parámetro? Para lograr resolver este problema, vamos a introducir el concepto de programación dinámica Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 7 / 61

Contenidos Programación Dinámica Programación Dinámica 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 8 / 61

Programación Dinámica Programación dinámica Programación Dinámica But do not despise the lore that has come down from distant years; for oft it may chance that old wives keep in memory word of things that once were needful for the wise to know. Celeborn the Wise, The Fellowship of the Ring, J. R. R. Tolkien La programación dinámica consiste, esencialmente, en una recursión con una suerte de memorización o cache. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 9 / 61

Programación Dinámica Programación dinámica Programación Dinámica Visión tradicional: La programación dinámica es una técnica que consiste en: Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 10 / 61

Programación Dinámica Programación dinámica Programación Dinámica Visión tradicional: La programación dinámica es una técnica que consiste en: Dividir un problema en dos o más subproblemas o reducirlo a una instancia más fácil de calcular del problema. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 10 / 61

Programación Dinámica Programación dinámica Programación Dinámica Visión tradicional: La programación dinámica es una técnica que consiste en: Dividir un problema en dos o más subproblemas o reducirlo a una instancia más fácil de calcular del problema. Resolver las instancias de cada subproblema de la misma manera (dividiendo en subproblemas o reduciendo a otra instancia) hasta llegar a un caso base. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 10 / 61

Programación Dinámica Programación dinámica Programación Dinámica Visión tradicional: La programación dinámica es una técnica que consiste en: Dividir un problema en dos o más subproblemas o reducirlo a una instancia más fácil de calcular del problema. Resolver las instancias de cada subproblema de la misma manera (dividiendo en subproblemas o reduciendo a otra instancia) hasta llegar a un caso base. Guardar el resultado de cada instancia del problema la primera vez que se calcula, para que cada vez que se vuelva a necesitar el valor de esa instancia ya esté almacenado, y no sea necesario calcularlo nuevamente. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 10 / 61

Programación Dinámica Programación dinámica Programación Dinámica Visión tradicional: La programación dinámica es una técnica que consiste en: Dividir un problema en dos o más subproblemas o reducirlo a una instancia más fácil de calcular del problema. Resolver las instancias de cada subproblema de la misma manera (dividiendo en subproblemas o reduciendo a otra instancia) hasta llegar a un caso base. Guardar el resultado de cada instancia del problema la primera vez que se calcula, para que cada vez que se vuelva a necesitar el valor de esa instancia ya esté almacenado, y no sea necesario calcularlo nuevamente. Cómo hacemos para calcular una sóla vez una función para cada parámetro, por ejemplo, en el caso de Fibonacci? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 10 / 61

Programación Dinámica Programación Dinámica Cálculo de Fibonacci mediante Programación Dinámica 1 int fibo[100]; 2 int calcfibo( int n) 3 { 4 i f (fibo [n]!= 1) 5 return fibo [n] ; 6 fibo [n] = calcfibo(n 2)+calcFibo(n 1); 7 return fibo [n] ; 8 } 9 int main() 10 { 11 for ( int i=0;i <100;i++) 12 fibo [ i ] = 1; 13 fibo [0] = 1; 14 fibo [1] = 1; 15 int fibo50 = calcfibo(50); 16 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 11 / 61

Programación Dinámica Programación Dinámica Ventajas de la Programación Dinámica La función que vimos recién que usa programación dinámica tiene una ventaja con respecto a la versión recursiva que vimos anteriormente: Llama menos veces a cada función Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 12 / 61

Programación Dinámica Programación Dinámica Ventajas de la Programación Dinámica La función que vimos recién que usa programación dinámica tiene una ventaja con respecto a la versión recursiva que vimos anteriormente: Llama menos veces a cada función Para calcular calcfibo(n-1) necesita calcular calcfibo(n-2), pero ya lo calculamos antes, por lo que no es necesario volver a llamar a calcfibo(n-3) y calcfibo(n-4) Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 12 / 61

Programación Dinámica Programación Dinámica Ventajas de la Programación Dinámica La función que vimos recién que usa programación dinámica tiene una ventaja con respecto a la versión recursiva que vimos anteriormente: Llama menos veces a cada función Para calcular calcfibo(n-1) necesita calcular calcfibo(n-2), pero ya lo calculamos antes, por lo que no es necesario volver a llamar a calcfibo(n-3) y calcfibo(n-4) Así podemos calcular calcfibo(50) mucho más rápido ya que este algoritmo es lineal mientras que el anterior era exponencial. Esta forma particularmente sencilla de implementar programación dinámica, es decir, mediante el agregado al código exacto de la recursión ingenua, un par de líneas para guardar y leer respuestas previas de la cache, se llama memoización (del inglés memoization). Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 12 / 61

Programación Dinámica Números combinatorios Programación Dinámica Ejemplo Otro ejemplo de un problema que puede ser resuelto mediante programación dinámica es el de los números combinatorios Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 13 / 61

Programación Dinámica Números combinatorios Programación Dinámica Ejemplo Otro ejemplo de un problema que puede ser resuelto mediante programación dinámica es el de los números combinatorios Cómo lo calculamos El combinatorio ( ) n k se puede calcular como n! k!(n k)!, pero si en lugar de un único combinatorio queremos precalcular una tabla completa de combinatorios, lo más práctico es usar el procedimiento del triángulo de pascal. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 13 / 61

Programación Dinámica Programación Dinámica Calculo recursivo del número combinatorio Algoritmo recursivo 1 int comb( int n, int k) 2 { 3 i f (k==0 k==n) 4 return 1; 5 else 6 return comb(n 1,k 1)+comb(n 1,k) ; 7 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 14 / 61

Programación Dinámica Programación Dinámica Calculo recursivo del número combinatorio Algoritmo recursivo 1 int comb( int n, int k) 2 { 3 i f (k==0 k==n) 4 return 1; 5 else 6 return comb(n 1,k 1)+comb(n 1,k) ; 7 } Este algoritmo tiene un problema. Cuál es el problema? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 14 / 61

Programación Dinámica Programación Dinámica Calculo recursivo del número combinatorio Algoritmo recursivo 1 int comb( int n, int k) 2 { 3 i f (k==0 k==n) 4 return 1; 5 else 6 return comb(n 1,k 1)+comb(n 1,k) ; 7 } Este algoritmo tiene un problema. Cuál es el problema? Calcula muchas veces el mismo número combinatorio. Cómo arreglamos esto? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 14 / 61

Programación Dinámica Programación Dinámica Número combinatorio calculado con programación dinámica Algoritmo con Programación Dinámica 1 int comb[100][100]; 2 void llenartablacombinatorioshasta( int n) 3 { 4 for ( int i = 0; i <= n; i++) 5 { 6 comb[ i ][0] = comb[ i ] [ i ] = 1; 7 for ( int k = 1; k < i ; k++) 8 comb[ i ] [k] = comb[ i 1][k] + comb[ i 1][k 1]; 9 } 10 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 15 / 61

Programación Dinámica Programación Dinámica Número combinatorio calculado con programación dinámica (continuado) Este algoritmo no utiliza memoización (según algunos autores, esta forma bottom-up es programación dinámica, pero memoización no). Esta forma es mucho más eficiente que memoización, cuando se calculan la mayoría de las entradas de la tabla cache. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 16 / 61

Programación Dinámica Superposición de subproblemas Programación Dinámica Los dos ejemplos vistos presentan una característica típica de la programación dinámica: La superposición de subproblemas. El beneficio de la programación dinámica se da justamente porque evitamos recalcular subproblemas que se superponen. Sin superposición de subproblemas, podríamos usar programación dinámica, pero la complejidad extra de la cache no aportaría nada, porque nunca se reutilizaría un subproblema ya calculado, y podríamos haber usado directamente una recursión común (divide and conquer). Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 17 / 61

Contenidos Programación Dinámica Principio de Optimalidad 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 18 / 61

Programación Dinámica Otro tipo de problemas Principio de Optimalidad Hasta ahora vimos problemas en los que hay que calcular una cantidad determinada. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 19 / 61

Programación Dinámica Otro tipo de problemas Principio de Optimalidad Hasta ahora vimos problemas en los que hay que calcular una cantidad determinada. En algunos casos lo que tenemos que calcular es el mínimo o máximo de alguna función objetivo, sobre un conjunto de soluciones posibles, es decir, resolver un problema de optimización. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 19 / 61

Programación Dinámica Otro tipo de problemas Principio de Optimalidad Hasta ahora vimos problemas en los que hay que calcular una cantidad determinada. En algunos casos lo que tenemos que calcular es el mínimo o máximo de alguna función objetivo, sobre un conjunto de soluciones posibles, es decir, resolver un problema de optimización. En estos casos para poder usar programación dinámica necesitamos asegurarnos de que la solución de los subproblemas sea parte de la solución de la instancia original del problema. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 19 / 61

Programación Dinámica Principio de optimalidad Principio de Optimalidad Definición Se dice que un problema cumple el principio de optimalidad de Bellman cuando en una o más partes de una solución óptima al mismo, debe aparecer necesariamente una solución óptima a un subproblema. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 20 / 61

Programación Dinámica Principio de optimalidad Principio de Optimalidad Definición Se dice que un problema cumple el principio de optimalidad de Bellman cuando en una o más partes de una solución óptima al mismo, debe aparecer necesariamente una solución óptima a un subproblema. Bellman, quien estudió la programación dinámica en 1953, afirmó que el principio de optimalidad es un requisito indispensable para poder aplicar esta técnica. Notar que justamente es el principio de optimalidad lo que nos permite utilizar recursión. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 20 / 61

Programación Dinámica Principio de optimalidad Principio de Optimalidad Definición Se dice que un problema cumple el principio de optimalidad de Bellman cuando en una o más partes de una solución óptima al mismo, debe aparecer necesariamente una solución óptima a un subproblema. Bellman, quien estudió la programación dinámica en 1953, afirmó que el principio de optimalidad es un requisito indispensable para poder aplicar esta técnica. Notar que justamente es el principio de optimalidad lo que nos permite utilizar recursión. Veamos un ejemplo de problema clásico. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 20 / 61

Programación Dinámica Viaje óptimo en matriz Principio de Optimalidad Supongamos que tenemos una matriz de n m, con números enteros, y queremos encontrar el camino de la esquina superior-izquierda, a la esquina inferior-derecha, que maximice la suma de las casillas recorridas. El camino está restringido a utilizar únicamente movimientos de tipo derecha y abajo. Cómo resolveríamos este problema? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 21 / 61

Programación Dinámica Viaje óptimo en matriz Principio de Optimalidad Supongamos que tenemos una matriz de n m, con números enteros, y queremos encontrar el camino de la esquina superior-izquierda, a la esquina inferior-derecha, que maximice la suma de las casillas recorridas. El camino está restringido a utilizar únicamente movimientos de tipo derecha y abajo. Cómo resolveríamos este problema? f (x, y) = M x,y + max(f (x 1, y), f (x, y 1)) f (1, y) = M 1,y + f (1, y 1)) f (x, 1) = M x,1 + f (x 1, 1)) f (1, 1) = M 1,1 Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 21 / 61

Programación Dinámica Viaje óptimo en matriz (camino) Principio de Optimalidad La recursión anterior lleva a un algoritmo de programación dinámica para calcular la suma óptima en el recorrido. Pero cómo recuperaríamos el camino en sí? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 22 / 61

Programación Dinámica Viaje óptimo en matriz (camino) Principio de Optimalidad La recursión anterior lleva a un algoritmo de programación dinámica para calcular la suma óptima en el recorrido. Pero cómo recuperaríamos el camino en sí? Y si quisiéramos el camino lexicográficamente mínimo? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 22 / 61

Programación Dinámica Viaje óptimo en matriz (camino) Principio de Optimalidad La recursión anterior lleva a un algoritmo de programación dinámica para calcular la suma óptima en el recorrido. Pero cómo recuperaríamos el camino en sí? Y si quisiéramos el camino lexicográficamente mínimo? Y si quisiéramos el camino número 420 en orden lexicográfico? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 22 / 61

Programación Dinámica Viaje óptimo en matriz (camino) Principio de Optimalidad La recursión anterior lleva a un algoritmo de programación dinámica para calcular la suma óptima en el recorrido. Pero cómo recuperaríamos el camino en sí? Y si quisiéramos el camino lexicográficamente mínimo? Y si quisiéramos el camino número 420 en orden lexicográfico? Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 22 / 61

Contenidos Programación Dinámica Visión constructiva 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 23 / 61

Programación Dinámica Visión constructiva de DP Visión constructiva En el ejemplo anterior, nos encontramos con que definimos la recursión de una cierta manera, pero después nos quedó al revés. Notar que si solamente quisiéramos calcular el resultado (numerito), daría lo mismo el orden o la recursión concreta. El problema surge al querer reconstruir el camino: Tenemos en mente un procedimiento de construcción de la solución Ese procedimiento está formado por una secuencia ordenada de pasos, que son parte del problema y queremos ser capaces de reconstruir Cada paso transforma un estado intermedio (o subproblema) en otro, durante el proceso de construcción de la solución. Pero nada de esto fue tenido en cuenta cuando pensamos la construcción! Por lo tanto, si nos importa reconstruir o razonar sobre el camino, se puede pensar programación dinámica de otra forma. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 24 / 61

Programación Dinámica Visión constructiva Visión constructiva de DP (continuado) Identificamos un proceso de construcción de la solución, identificando estados y transiciones. El estado debe contener toda la información relevante que necesitaremos para poder decidir las transiciones óptimas. Las transiciones posibles no deben producir ciclos, (o nuestra recursión se volvería infinita). Ahora cada estado se corresponde a una entrada en la tabla o cache de nuestro algoritmo de DP, y las transiciones vienen dadas por las llamadas recursivas. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 25 / 61

Programación Dinámica Visión constructiva Visión constructiva de DP (continuado) Si aplicamos esto al problema anterior, la función y estados nos quedan al revés que antes: Esto es de atrás para adelante, pero notar que nos permite reconstruir el camino en el orden natural. Ahora sí podemos encontrar el camino lexicográficamente mínimo! También podemos encontrar si utilizamos este orden, el camino 420 en orden lexicográfico, pero dejemos eso para más adelante. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 26 / 61

Contenidos Programación Dinámica 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 27 / 61

Programación Dinámica Mismo problema de antes, pero ahora podemos hacer hasta K movimientos del tipo izquierda. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 28 / 61

Programación Dinámica Mismo problema de antes, pero ahora podemos hacer hasta K movimientos del tipo izquierda. Mismo problema de arriba, pero además podemos usar hasta W elefantes mágicos, que nos permiten hacer un movimiento de alfil de ajedrez en la matriz. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 28 / 61

Programación Dinámica Mismo problema de antes, pero ahora podemos hacer hasta K movimientos del tipo izquierda. Mismo problema de arriba, pero además podemos usar hasta W elefantes mágicos, que nos permiten hacer un movimiento de alfil de ajedrez en la matriz. Mismo problema de arriba, pero además podemos usar hasta Z globos aerostáticos, que nos permiten hacer un movimiento de torre de ajedrez en la matriz. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 28 / 61

(más) Programación Dinámica Subset sum: Dados n números enteros positivos, decidir si se puede obtener una suma S usando algunos de ellos (a lo sumo una vez cada uno). Knapsack o problema de la mochila: Dados objetos con peso y valor, queremos meter el máximo valor posible en una mochila que soporta hasta P de peso. Resolvamos ambos pensándolos de la manera constructiva ( Por ejemplo, porque nos piden la solución lexicográficamente más chica, y no queremos tener que reescribir todo al final porque nos quedó al revés!) Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 29 / 61

Resumiendo Programación Dinámica Hemos visto dos maneras de pensar la programación dinámica: Tradicional (recursiva) Pensando en un proceso de construcción de solución (constructiva) Si solo interesa el numerito, usar cualquier opción de las anteriores (la que resulte más natural o fácil). Si interesa reconstruir el camino, y muy especialmente si interesa algún camino en orden lexicográfico, pensarlo de la manera constructiva puede ser útil. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 30 / 61

Programación Dinámica Resumiendo (continuado) Y dos maneras de implementarla: Memoización (La más fácil, no hay que pensar en qué orden iterar los subproblemas. Buena cuando solo se usan algunos pocos subproblemas, difíciles de caracterizar o iterar) Bottom-up (Más eficiente si se usan casi todos los estados posibles, pero requiere poder iterar todos los estados relevantes, y pensar con cuidado el orden de recorrida) Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 31 / 61

Contenidos Programación Dinámica Problemas 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 32 / 61

Problemas Programación Dinámica Problemas Algunos problemas para practicar programación dinámica. http://codeforces.com/problemset/problem/225/c http://codeforces.com/problemset/problem/163/a http://goo.gl/arne7 http://goo.gl/bjtpz Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 33 / 61

Contenidos Dinámicas en rangos Introducción 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 34 / 61

Introducción Dinámicas en rangos Introducción El patrón de Dinámicas en rangos es un patrón típico que aparece mucho. Consiste en estados (o subproblemas) de la forma (a, b), es decir, intervalos o rangos. Lo mejor es estudiar algunos ejemplos concretos. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 35 / 61

Contenidos Dinámicas en rangos 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 36 / 61

ABB óptimo Dinámicas en rangos Dada una secuencia de valores ordenados v 1 < v 2 < < v n, junto a sus frecuencias o probabilidades de aparición f 1,, f n, dar un algoritmo que compute un árbol binario de búsqueda que minimice el tiempo (cantidad de comparaciones realizadas = profundidad) esperado para encontrar un elemento. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 37 / 61

Parentesis Dinámicas en rangos Dada una cadena de caracteres {, }, [, ], ( y ), de longitud par, dar la mínima cantidad de reemplazos de caracteres que se le deben realizar a este string para dejar una secuencia bien parenteseada. Una secuencia bien parenteseada T se puede formar con las siguientes reglas a partir de secuencias bien parenteseadas S y S 2 : T = T = SS 2 T = (S) T = [S] T = {S} Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 38 / 61

Contenidos Dinámicas en rangos Tarea 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 39 / 61

Tarea Dinámicas en rangos Tarea Problema de la IOI de México 2006 http://ioinformatics.org/locations/ioi06/contest/ day2/mexico/mexico.pdf Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 40 / 61

Contenidos Máscaras de bits Iterando sobre subconjuntos 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 41 / 61

Subconjuntos Máscaras de bits Iterando sobre subconjuntos Subconjuntos de un conjunto Es muy común que aparezcan problemas en los que hay que iterar sobre los subconjuntos de un conjunto, y que para calcular una función sobre un subconjunto haya que calcularla previamente sobre sus subconjuntos, para esto utilizamos programación dinámica. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 42 / 61

Subconjuntos Máscaras de bits Iterando sobre subconjuntos Subconjuntos de un conjunto Es muy común que aparezcan problemas en los que hay que iterar sobre los subconjuntos de un conjunto, y que para calcular una función sobre un subconjunto haya que calcularla previamente sobre sus subconjuntos, para esto utilizamos programación dinámica. Problema de los Peces Hay n peces en el mar. Cada un minuto se encuentran dos peces al azar (todos los pares de peces tienen la misma probabilidad) y si los peces que se encuentran son el pez i y el pez j, entonces el pez i se come al pez j con probabilidad p[i][j] y el pez j se come al pez i con probabilidad p[j][i]. Sabemos que p[i][j] + p[j][i] = 1 si i j y p[i][i] = 0 para todo i. Cual es la probabilidad de que sobreviva el pez 0? Sabemos que hay a lo sumo 18 peces. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 42 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Podemos iterar sobre los subconjuntos de un conjunto usando vectores que tengan los elementos del conjunto y crear vectores con todos los subconjuntos, pero esto es muy caro en tiempo y memoria. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 43 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Podemos iterar sobre los subconjuntos de un conjunto usando vectores que tengan los elementos del conjunto y crear vectores con todos los subconjuntos, pero esto es muy caro en tiempo y memoria. Un subconjunto de un conjunto se caracteriza por tener (1) o no tener (0) a cada elemento del conjunto. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 43 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Podemos iterar sobre los subconjuntos de un conjunto usando vectores que tengan los elementos del conjunto y crear vectores con todos los subconjuntos, pero esto es muy caro en tiempo y memoria. Un subconjunto de un conjunto se caracteriza por tener (1) o no tener (0) a cada elemento del conjunto. Por ejemplo, si tenemos un conjunto de 10 elementos, sus subconjuntos pueden ser representados como números entre 0 y 1023 (2 10 1). Para cada número, si el i-ésimo bit en su representación binaria es un 1 lo interpretamos como que el i-ésimo pez del conjunto está en el subconjunto representado por ese número. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 43 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Cuando un número representa un subconjunto de un conjunto según los ceros o unos de su representación binaria se dice que este número es una máscara de bits Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 44 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Cuando un número representa un subconjunto de un conjunto según los ceros o unos de su representación binaria se dice que este número es una máscara de bits Para ver si un número a representa un subconjunto del subconjunto que representa un número b tenemos que chequear que bit a bit si hay un 1 en a hay entonces un 1 en b Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 44 / 61

Máscaras de bits Máscaras de bits Iterando sobre subconjuntos Cuando un número representa un subconjunto de un conjunto según los ceros o unos de su representación binaria se dice que este número es una máscara de bits Para ver si un número a representa un subconjunto del subconjunto que representa un número b tenemos que chequear que bit a bit si hay un 1 en a hay entonces un 1 en b Esto se puede chequear viendo que a OR b sea igual a b donde OR representa al OR bit a bit Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 44 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos Para resolver el problema de los peces, podemos tomar cada subconjunto de peces, y ver qué pasa ante cada opción de que un pez se coma a otro. Esto nos genera un nuevo subconjunto de peces para el cual resolver el problema. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 45 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos Para resolver el problema de los peces, podemos tomar cada subconjunto de peces, y ver qué pasa ante cada opción de que un pez se coma a otro. Esto nos genera un nuevo subconjunto de peces para el cual resolver el problema. Cuando llegamos a un subconjunto de un sólo pez, si el pez es el pez 0, entonces la probabilidad de que sobreviva el pez 0 es 1, sino es 0. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 45 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos Para resolver el problema de los peces, podemos tomar cada subconjunto de peces, y ver qué pasa ante cada opción de que un pez se coma a otro. Esto nos genera un nuevo subconjunto de peces para el cual resolver el problema. Cuando llegamos a un subconjunto de un sólo pez, si el pez es el pez 0, entonces la probabilidad de que sobreviva el pez 0 es 1, sino es 0. En cada paso, la probabilidad de que sobreviva el pez 0 es, la probabilidad de reducir el problema a otro subconjunto, por la probabilidad de que sobreviva dado ese subconjunto. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 45 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos 1 double dp[1<<18]; 2 int n; 3 double p[18][18]; 4 5 int main() 6 { 7 forn( i,(1<<18)) 8 dp[ i ] = 1; 9 cin >> n; 10 forn( i,n) 11 forn( j,n) 12 cin >> p[ i ] [ j ] ; 13 printf ( " %.6l f \n", f((1<<n) 1)) ; 14 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 46 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos 1 double f ( int mask) { 2 i f (dp[mask] > 0.5) return dp[mask] ; 3 int vivos = 0; 4 forn( i,n) i f ((mask>>i ) %2==1) vivos++; 5 double pares = (vivos (vivos 1)) /2; 6 i f (vivos==1) { 7 i f (mask==1) dp[mask] = 1.; 8 else dp[mask] = 0.; 9 return dp[mask] ; 10 } 11 dp[mask] = 0.; 12 forn( i,n) forn( j, i ) i f ((mask>>i ) %2==1&&(mask>>j ) %2==1) { 13 i f ( i!=0 && j!=0) dp[mask] += ( f (mask^(1<<i ) ) p[ j ] [ i ]+f (mask^(1<<j ) ) p[ i ] [ j ]) /pares; 14 else i f ( i==0) dp[mask] += f (mask^(1<<j ) ) p[ i ] [ j ] /pares; 15 else i f ( j==0) dp[mask] += f (mask^(1<<i ) ) p[ j ] [ i ] /pares; 16 } 17 return dp[mask] [pez] ; 18 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 47 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos Supongamos que ahora tenemos que resolver el mismo problema, pero en lugar de para un sólo pez, para todos los peces. Podríamos usar el mismo código y resolver el problema 18 veces, pero hay algo más eficiente. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 48 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos Supongamos que ahora tenemos que resolver el mismo problema, pero en lugar de para un sólo pez, para todos los peces. Podríamos usar el mismo código y resolver el problema 18 veces, pero hay algo más eficiente. Lo que hicimos anteriormente fue movernos de un conjunto a sus subconjuntos. Lo que vamos a hacer ahora es movernos de un conjunto a sus superconjuntos. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 48 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos 1 double dp[1<<18]; 2 int n; 3 double p[18][18]; 4 5 int main() 6 { 7 cin >> n; 8 forn( i,n) 9 forn( j,n) 10 cin >> p[ i ] [ j ] ; 11 forn( i,(1<<n) ) 12 dp[ i ] = 1; 13 dp[(1<<n) 1] = 1.; 14 forn( i,n) 15 printf ( " %.6l f \n", f(1<<i ) ) ; 16 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 49 / 61

Máscaras de bits Problema de los Peces Iterando sobre subconjuntos 1 double f ( int mask) 2 { 3 i f (dp[mask]> 0.5) 4 return dp[mask] ; 5 dp[mask] = 0; 6 int vivos = 1; 7 forn( i,n) 8 i f ((mask>>i ) %2==1) 9 vivos++; 10 double pares = (vivos (vivos 1)) /2; 11 forn( i,n) 12 forn( j,n) 13 { 14 i f ((mask&(1<<i ) )!=0&&(mask&(1<<j ) )==0) 15 dp[mask] += f (mask (1<< j ) ) p[ i ] [ j ] /pares; 16 } 17 return dp[mask] ; 18 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 50 / 61

Contenidos Máscaras de bits 1 Programación Dinámica Recursión Programación Dinámica Principio de Optimalidad Visión constructiva Problemas 2 Dinámicas en rangos Introducción Tarea 3 Máscaras de bits Iterando sobre subconjuntos 4 Longest Increasing Subsequence 5 Bonus track Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 51 / 61

Máscaras de bits Compañeros de grupo Enunciado En una clase hay 2n alumnos (n 8) y tienen que hacer trabajos prácticos en grupos de a 2. El i-ésimo alumno vive en el punto (x i, y i ) de la ciudad y tarda (x i x j ) 2 + (y i y j ) 2 minutos en llegar a la casa del j-ésimo alumno. El profesor sabe que los alumnos se reunen para hacer los trabajos prácticos en la casa de uno de los dos miembros del grupo. Por eso decide que la suma de las distancias entre compañeros de grupo debe ser mínima. Dar esta distancia. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 52 / 61

Máscaras de bits Compañeros de grupo Enunciado En una clase hay 2n alumnos (n 8) y tienen que hacer trabajos prácticos en grupos de a 2. El i-ésimo alumno vive en el punto (x i, y i ) de la ciudad y tarda (x i x j ) 2 + (y i y j ) 2 minutos en llegar a la casa del j-ésimo alumno. El profesor sabe que los alumnos se reunen para hacer los trabajos prácticos en la casa de uno de los dos miembros del grupo. Por eso decide que la suma de las distancias entre compañeros de grupo debe ser mínima. Dar esta distancia. Como son 16 alumnos podemos iterar sobre los subconjuntos, en cada paso tomamos una máscara y le sacamos dos bits (que representan dos alumnos). Resolvemos el problema con la nueva máscara y le sumamos la distancia entre la casa de esos dos alumnos. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 52 / 61

Máscaras de bits Problema del viajante de comercio Enunciado Un viajante debe recorrer n 20 ciudades exactamente una vez cada una, formando un ciclo para vender sus productos en cada ciudad. Conociendo la tabla de distancias entre cada par de ciudades, proponer un ciclo que minimice la longitud total recorrida. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 53 / 61

Máscaras de bits Problema del viajante de comercio Enunciado Un viajante debe recorrer n 20 ciudades exactamente una vez cada una, formando un ciclo para vender sus productos en cada ciudad. Conociendo la tabla de distancias entre cada par de ciudades, proponer un ciclo que minimice la longitud total recorrida. Podemos encontrar una solución O(2 n n 2 ) utilizando programación dinámica. Notar que esto es muchísimo mejor que el sencillo O(n!). Como estado podemos tomar la ciudad actual, y el conjunto (máscara) de las ciudades ya recorridas, asumiendo que se empezó de una ciudad fija arbitraria. n 2 n n 2 n! 5 800 120 10 102400 3628800 15 7372800 1307674368000 20 419430400 2432902008176640000 Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 53 / 61

Tarea Máscaras de bits Tutorial de topcoder: A bit of fun: fun with bits, por Bruce Merry http://community.topcoder.com/tc?module=static& d1=tutorials&d2=bitmanipulation https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&itemid=8&page=show_ problem&problem=2451 http://goo.gl/iktih Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 54 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Subsecuencia creciente más larga El problema consiste en, dada una secuencia de números, encontrar la subsecuencia de números que aparezcan de manera creciente y que sea lo más larga posible. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 55 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Subsecuencia creciente más larga El problema consiste en, dada una secuencia de números, encontrar la subsecuencia de números que aparezcan de manera creciente y que sea lo más larga posible. Solución cuadrática La solución trivial a este problema consiste en calcular en cada paso, la subsecuencia creciente más larga que usa los primeros i números de la secuencia, recorriendo la solución para todos los j < i. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 55 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Existe una solución O(n log n) donde n es la longitud de la secuencia. Para implementar esa solución vamos a tener tres vectores: el input (al que llamamos seq), m y p. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 56 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Existe una solución O(n log n) donde n es la longitud de la secuencia. Para implementar esa solución vamos a tener tres vectores: el input (al que llamamos seq), m y p. En la i-ésima iteración, vamos a tener en m[j] un k < i tal que hay una subsecuencia de largo j que termina en k, con seq[k] mínimo, mientras que m[0] comienza inicializado en -1. Observación: m está ordenado por los valores de seq[m[i]] (esto nos permite hacer búsqueda binaria en tales valores). Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 56 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Existe una solución O(n log n) donde n es la longitud de la secuencia. Para implementar esa solución vamos a tener tres vectores: el input (al que llamamos seq), m y p. En la i-ésima iteración, vamos a tener en m[j] un k < i tal que hay una subsecuencia de largo j que termina en k, con seq[k] mínimo, mientras que m[0] comienza inicializado en -1. Observación: m está ordenado por los valores de seq[m[i]] (esto nos permite hacer búsqueda binaria en tales valores). En la i-ésima posicion de p vamos a ir guardando el elemento anterior al i-ésimo en la subsecuencia creciente más larga que termina en el i-ésimo elemento del input. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 56 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga 1 vector<int> lis () 2 { 3 int n = seq.size(), L = 0; m.resize(n+1); m[0] = 1; p.resize(n) ; 4 for ( int i =0;i<n; i++){ 5 int j = bs(l,seq[ i ]) ; 6 p[ i ] = m[ j ] ; 7 i f ( j==l input [ i ]<seq[m[ j +1]]){ 8 m[ j+1] = i ; 9 L = max(l, j+1); 10 } 11 } 12 vector<int> res; 13 int t = m[l] ; 14 while( t!= 1){ 15 res.push_back(seq[ t ]) ; 16 t = p[ t ] ; 17 } 18 reverse(res.begin(),res.end() ) ; 19 return res; 20 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 57 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga 1 int bs( int L, int num) 2 { 3 int mx = L+1, mn = 0; 4 while(mx mn>1) 5 { 6 int mid = (mx+mn) /2; 7 i f (seq[m[mid]]<num) 8 mn = mid; 9 else 10 mx = mid; 11 } 12 return mn; 13 } Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 58 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Observemos que m va a estar definido para todo j < L y que m[j] está en el rango de vec para todo 0 < j L. Además en la búsqueda binaria nunca evaluamos seq[m[0]]. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 59 / 61

Longest Increasing Subsequence Subsecuencia creciente más larga Observemos que m va a estar definido para todo j < L y que m[j] está en el rango de vec para todo 0 < j L. Además en la búsqueda binaria nunca evaluamos seq[m[0]]. También podemos ver que p va a estar siempre definido para todo 0 i < n. Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 59 / 61

Tarea Longest Increasing Subsequence http://www.spoj.com/problems/supper/ http://www.spoj.com/problems/lis2/ Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 60 / 61

Bonus track Cosas de las que se puede hablar si sobra tiempo y hay que llenar Dinámicas con frente. Cálculo de la iésima solución lexicográficamente Juan Cruz Piñero (UBA) Programación Dinámica TC 2017 61 / 61