Tema 3. Resolución de problemas 3.1. TÉCNICAS DE RESOLUCIÓN DE PROBLEMAS .......................................................90 3.2. ESQUEMAS BÁSICOS DE RESOLUCIÓN DE PROBLEMAS DE SECUENCIAS ..97 RECORRIDO COMPLETO DE UNA SECUENCIA ..............................................................................98 BÚSQUEDA DE ELEMENTO DISTINGUIDO ..................................................................................101 Propiedad de los elementos de la secuencia .........................................................................105 3.3. EJEMPLOS DE TRATAMIENTO DE SECUENCIAS ................................................107 EJERCICIOS ...........................................................................................................................110 90 Programación I 3.1. Técnicas de resolución de problemas Enfrentarnos a un problema grande puede dejarnos perplejos (como un escritor al iniciar la escritura de una novela) La mejor forma de empezar es escribir en un papel con tus propias palabras qué nos piden. La mayoría de bloqueos mentales provienen de entender mal el problema. Escribir el problema con tus palabras ayuda a entenderlo mejor, centrándote en cada parte por separado. Esta escritura con tus palabras te ayuda a: • Encontrar partes que te suenen haber resuelto ya, o haber resuelto algo parecido. • Determinar cuestiones que no se entienden bien, y habrá que pedir que nos aclaren. • Agrupar tratamientos. Esta agrupación de tareas puede venir bien para dividir el problema en subproblemas. • Podemos agrupar los datos que se introducen por un lado y los resultados por otro. Estos serán los estados de partida y final desde donde empezar a buscar objetivos intermedios. Especificar bien el problema. Establecer claramente cuáles son los datos y cuáles los resultados. Tema 3 – Resolución de Problemas 91 Programación I Resolución de problemas algorítmicos Idear un algoritmo que resuelva un problema no siempre es una "labor limpia", con pasos siempre hacia adelante. Es importante realizar un estudio de casos críticos en los datos del problema. Normalmente se trata de una tarea de prueba y error, donde se realizan varios intentos de solución y correcciones sobre ellos. Para cada intento de solución, hay que comprobar si de verdad resuelve el problema. La solución algorítmica suele ser el resultado de numerosos intentos, de descartar partes y volverlas a reconstruir. La resolución de problemas algorítmicos lleva su tiempo. En algunas ocasiones puede convenir volver a empezar el diseño de la solución desde el principio. Si el problema es mínimamente complejo: La tarea que menos tiempo lleva es traducir la solución a un lenguaje de programación. Tema 3 – Resolución de Problemas 92 Programación I ¿Qué técnicas se pueden utilziar? En la vida ordinaria tratamos con algoritmos. Tenemos experiencia siguiendo los pasos de algoritmos desarrollados por otros: una receta, un juego de mesa, montar una maqueta, renovar el dni, matricularse en la facultad, ... En programación, la fase de resolución de problemas trata de diseñar soluciones. Estas "técnicas" pueden verse como la simple aplicación del sentido común a la hora de inventar soluciones para los problemas: • Hacer preguntas • Pensar si alguna vez resolvimos algo semejante • Analizar qué medios nos permiten alcanzar la meta • Divide y vencerás • Juntar piezas existentes • Combinar/fusionar soluciones Tema 3 – Resolución de Problemas 93 Programación I • Hacer preguntas ¡Antes de empezar a pensar cómo resolverlo! Hay que aclararse bien de qué nos están pidiendo y qué no nos piden. Quien debe respondernos es la persona que nos solicita la tarea. Ejemplos: ¿Qué datos nos proporcionan? ¿Qué formato van a tener esos datos? ¿Los tipos de los datos? ¿Qué resultados deberemos obtener? ¿Qué mensajes de error debemos presentar? ¿Cuántas veces habrá de repetirse tal o cuál proceso? Tema 3 – Resolución de Problemas 94 Programación I • Pensar si alguna vez resolvimos algo semejante. No reinventemos la rueda cada vez. Apliquemos soluciones similares ante problemas parecidos. A veces nos puede servir como fuente de inspiración conocer una solución no algorítmica a un problema que se nos antoje similar (al menos puede servir como punto de comienzo). Los mejores programadores suelen ser personas con experiencia en resolver problemas de organización variopintos. • Analizar qué medios nos permiten alcanzar la meta Conocemos el estado de partida (datos del problema) y el estado a alcanzar (resultados). El problema radica en encontrar los pasos intermedios que nos lleven desde el principio hasta el final. Se nos ocurrirán diferentes formas de avanzar pasos (en avión, en tren, en autostop, andando...). Habrá que descartar ideas antes de trabajar los detalles. La estrategia global consiste en determinar objetivos intermedios y los medios para llegar desde uno al siguiente. Tema 3 – Resolución de Problemas 95 Programación I • Divide y vencerás Consiste en dividir un problema grande en un conjunto de problemas más pequeños, y por lo tanto más sencillos. Cada trozo de problema se resuelve por separado como si fuera el problema completo. Podemos seguir aplicando la estrategia “divide y vencerás” a cualquier problema más pequeño generado, mientras lo veamos conveniente. • Juntar piezas existentes Se trata de buscar piezas que resuelvan partes pequeñas del problema y utilizarlas en la construcción de la solución. Es una combinación de las técnicas de "pensar si alguna vez resolvimos algo semejante" y "divide y vencerás". Tema 3 – Resolución de Problemas 96 Programación I • Combinar/Fusionar soluciones Por combinar soluciones se entiende que en lugar de realizar problemas por separado, se realicen conjuntamente, aprovechando estructuras de control comunes, ciclos, condicionales, etc. Por ejemplo en el problema de hallar la media aritmética, podemos partir de dos soluciones ya hechas: cálculo de la suma y contar el número de elementos. En ambas soluciones parciales es necesario recorrer todos los valores de una secuencia, bien para sumarlos o bien para contarlos. En lugar de calcular primero la suma y luego contar los elementos, se pueden ir calculando ambas cosas al mismo tiempo (en un mismo ciclo). Tema 3 – Resolución de Problemas 97 Programación I 3.2. Esquemas básicos de resolución de problemas de secuencias Ante problemas similares ideamos algoritmos similares entre sí. Con un "esquema de programas" tratamos de plasmar una idea de solución para un tipo de problemas. Sea S una secuencia de elementos S= (s1, s2, s3, ..., sn), donde: 0 <= n. Es decir la secuencia puede que no tenga ningún elemento, secuencia vacía. n no es conocido. Es decir, no se sabe al comenzar a tratar la secuencia cuántos elementos tiene. Vamos a trabajar con dos esquemas típicos: • Recorrido completo de una secuencia • Búsqueda de un elemento distinguido Tema 3 – Resolución de Problemas 98 Programación I Recorrido completo de una secuencia Recorrido completo significa tratar TODOS los elementos de una secuencia Esquemas básicos Inicializar el proceso Inicializar recorrido Mientras queden elementos por tratar Tomar y actualizar el siguiente elemento Tratar el elemento //modificar el proceso Fin Tratar el resultado Inicializar el proceso Inicializar recorrido Repetir Salir si no quedan elementos por tratar Tomar y actualizar el siguiente elemento Tratar el elemento Fin Tratar el resultado Antes de Tomar y actualizar el siguiente elemento es necesario saber que ese elemento existe. Tema 3 – Resolución de Problemas 99 Programación I Recorrer1. Calcular la media aritmética de los números de la secuencia de entrada. Suma 0, num_elem 0 Mientras haya números por leer leer número Suma Suma + número incrementar num_elem Fin escribir "Media aritmetica" Suma/num_elem Suma 0, num_elem 0 Repetir Salir si no quedan números por leer leer número Suma Suma + número incrementar num_elem Fin escribir "Media aritmetica" Suma/num_elem Inicializar el proceso- Suma 0, num_elem 0 Inicializar recorrido- No es necesario hace nada para poder luego acceder a los elementos Tomar y actualizar el siguiente elemento- leer número asigna a la variable número un valor y se sitúa para poder leer el siguiente elemento Tratar el elemento//Modificar el proceso- Suma Suma + número, incrementar num_elem, acumular el nuevo valor de número en Suma y contar otro elemento mas en num_elem Tratar el resultado- Suma/num_elem, es necesario hacer una operación para obtener el valor requerido. Tema 3 – Resolución de Problemas 100 Programación I Recorrer2: Encontrar el mínimo y máximo de la secuencia de números naturales de entrada. Max 0, Min al mayor natural Max 0, Min al mayor natural Mientras queden números por leer leer número Si número > Max Max número Fin Si número < Min Min número Fin Fin Mientras Repetir Salir si no quedan más números por leer leer número Si número > Max Max número Fin Si número < Min Min número Fin Fin Repetir escribir "máximo: " Max "mínimo: " Min escribir "máximo: " Max "mínimo: " Min Tema 3 – Resolución de Problemas 101 Programación I Búsqueda de elemento distinguido Búsqueda de un elemento significa tratar algunos elementos de una secuencia HASTA encontrar uno determinado. Esquemas básicos Esquema Búsqueda1- cuando se desconoce si el elemento está o no en la secuencia Inicializar el proceso Inicializar recorrido Mientras hay elementos por tratar y no se ha encontrado el elemento Tomar y actualizar el siguiente elemento Tratar el elemento Fin Tratar el resultado Inicializar el proceso Inicializar recorrido Repetir Salir si no hay elementos por tratar o se ha encontrado el elemento Tomar y actualizar el siguiente elemento Tratar el elemento Fin Tratar el resultado Observar que la condición de entrada al bucle mientras es la negación de la condición de salida del bucle repetir y viceversa. Tema 3 – Resolución de Problemas 102 Programación I Esquema Búsqueda2- cuando se conoce que el elemento SÍ está en la secuencia. Es decir, en la especificación del problema tendremos: Especificación (parcial) Entrada: Secuencia S= (s1, s2, s3, ..., sn), elemento E Pre: i (1<= i <= n E= si) La condición de entrada/salida de los bucles respectivos, no debe ser compuesta. Bastará con preguntar si ya hemos encontrado el elemento que nos aseguran que está en la secuencia. Inicializar el proceso Inicializar recorrido Mientras no se ha encontrado el elemento Tomar y actualizarel siguiente elemento Tratar el elemento Fin Tratar el resultado Tema 3 – Resolución de Problemas Inicializar el proceso Inicializar recorrido Repetir Salir si se ha encontrado el elemento Tomar y actualizar el siguiente elemento Tratar el elemento Fin Tratar el resultado 103 Programación I Distin1. Dada una secuencia de enteros contar cuántos números negativos hay antes del primer cero de la secuencia de entrada o hasta el final si no hay 0. Número 1 (valor distinto de cero) contador 0 Mientras hay números por leer y Número no es cero leer Número si Número < 0 incrementar contador fin escribir contador La secuencia puede ser vacía Esquema1 Si me aseguran que hay al menos un 0 en la secuencia. Además la secuencia no podrá ser vacía. Esquema 2 contador 0 repetir leer Número // ¿puedo leer? salir si Número es cero si Número < 0 incrementar contador fin escribir contador Tema 3 – Resolución de Problemas 104 Programación I Distin2. En la entrada tenemos un número inicial y una secuencia de números. Indicar por pantalla si el número inicial se encuentra en la secuencia. Especificación Entrada: elemento E y Secuencia S= (s1, s2, s3, ..., sn), en la entrada estándar. Pre: Salida: Un booleano, en la salida estándar. Post: será cierto sii i (1<= i <= n E= si) Diseño leer núm_inicial número núm_inicial + 1 (valor distinto al inicial) mientras hay números por leer y número /núm_inicial // número NO encontrado leer número Fin Escribir “El numero inicial “ Si número /= núm_inicial escribir "no se encuentra" Si no escribir "se encuentra" Ejercicio: ¿Cómo cambiaría la solución dada si en la pre se indicara i (1<= i < n si <= si+1), es decir, que la secuencia está ordenada crecientemente?¿Y si i (1<= i < n si >= si+1), es decir, la secuencia está ordenada decrecientemente? Tema 3 – Resolución de Problemas 105 Programación I Propiedad de los elementos de la secuencia Se quiere conocer si TODOS los elementos de la secuencia cumplen una determinada propiedad Esquema1: Comprobar si todos los números de la secuencia de entrada son múltiplos de 2000 o de 5000. ¿Con qué esquema encaja?, ¿Recorrido completo o búsqueda de elemento? Todos_múltiplos cierto Todos_múltiplos cierto Mientras haya números por leer y Todos_múltiplos Repetir Salir si no quedan más números por leer or not Todos_múltiplos leer número leer número si número no es múltiplo de 2000 o de 5000 si número no es múltiplo de 2000 o de 5000 Todos_multiplos falso Todos_multiplos falso Fin Fin Como siempre las soluciones con "mientras" y con "repetir" sólo difieren en la condición: una es la negación de la otra (condición de continuar frente a condición de detenerse). En este caso, la condición de repetir se obtiene de la negación de la condición de mientras aplicando "de Morgan" (y viceversa) Tema 3 – Resolución de Problemas 106 Programación I Esquema2: Dada una serie de números a la entrada, escribir la tabla de multiplicar de cada número. Por ejemplo si los números leídos son el 1 y el 3 escribir 1x1=1 1x2=2 … 3x1=3 3x2=6 Evidentemente, es un recorrido completo de todos los elementos de la secuencia. Mientras hay números por leer Leer Número Para cada Multiplicador entre 1 y 10 escribir Número " x " Multiplicador escribir " = " Número * Multiplicador fin para fin mientras ¿Cómo cambiaría el diseño si tuviésemos implementado el subprograma tabla_multiplicar_num que escribe la tabla de multiplicar del número que se le pasa como parámetro? Tema 3 – Resolución de Problemas 107 Programación I 3.3. Ejemplos de tratamiento de secuencias Secuencias1. Suma todos los números que se introduzcan por teclado. Suma 0 Mientras haya números por leer leer Número Suma Suma + Número Fin Suma 0 Repetir Salir si not(hay números por leer) leer Número Suma Suma + Número Fin Secuencias2. Contar cuántos números de los introducidos por teclado son negativos: Contador 0 Repetir Salir si no hay más números por leer leer Número Si Número < 0 incrementar Contador Fin Tema 3 – Resolución de Problemas 108 Programación I Secuencias3. Dada una secuencia de números, ordenados de menor a mayor, contar cuántos son menores que 50: Inicializar Contador y Número a 0 Repetir Salir si no hay números por leer o Número >= 50 leer Numero si Número<50 entonces incrementar contador finSi Fin Tema 3 – Resolución de Problemas Inicializar Contador y Número a 0 Mientras hay números por leer y Número < 50 leer Numero si Número<50 entonces incrementar contador finSi Fin Programación I 109 Secuencias4: Cuántos números, entre los 100 primeros de la secuencia de entrada, están entre 5 y 10. (Nota: el decir entre los 100 primeros no significa que hay al menos 100). Núm_leidos 0 Contador 0 Repetir Salir si Núm_leidos=100 o no quedan números por leer Leer Número Incrementar Núm_leidos Si Número >= 5 y <= 10 Incrementar Contador Fin Tema 3 – Resolución de Problemas 110 Programación I EJERCICIOS 1. Especifica y diseña (en algunos casos completa) TODOS los ejemplos que han aparecido en este tema. 2. Especifica los siguientes problemas (cabecera y pre/pos) y diseña el algoritmo correspondiente a. En la entrada estándar viene una secuencia de números terminada en cero. El programa escribe en la salida estándar (un subprograma para cada opción): i. el mínimo de todos ellos (sin incluir el cero). ii. el máximo de todos ellos. iii. la media de los valores. b. En la entrada estándar viene una secuencia de números. El programa escribe en la salida estándar los que son (un subprograma para cada opción): i. primos y cuántos primos hay en dicha secuencia, ii. perfectos, y iii. opulentos y cuántos perfectos hay en la secuencia. Tema 3 – Resolución de Problemas Programación I 111 c. En la entrada estándar tenemos una secuencia de caracteres terminada en punto. El programa devuelve: i. el número de vocales en dicha secuencia. ii. el número de consonantes de dicha secuencia. iii. el número de caracteres de la secuencia (excluyendo el ‘.’). d. En la entrada estándar viene una secuencia de pares (string y carácter: si, ci). El subprograma devuelve en la salida estándar por cada si, los caracteres de si, distintos de ci. Tema 3 – Resolución de Problemas