Cómo leer un enunciado

Enterate del próximo post
Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.

Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.
Un mensaje que pide hacer las compras de la semana casi nunca contiene solo la lista de lo que hace falta. Junto con las cantidades y los productos suele venir un comentario sobre el clima, la mención de un compromiso para la tarde, o el recuerdo de algo que pasó en el supermercado la semana anterior. Separar esa mezcla y quedarse solo con lo que realmente hay que comprar - qué producto, cuánta cantidad - es, en esencia, la misma operación que leer un enunciado de programación: hay información que participa de la solución e información que solo la acompaña.
El post anterior definió qué es un algoritmo y qué tres condiciones tiene que cumplir. Antes de escribir el primer paso de uno, hace falta poder leer bien el problema que ese algoritmo va a resolver. Esa lectura es una habilidad propia, distinta de escribir pasos, y suele ser la que menos atención recibe.
Leer un enunciado bien significa separar tres cosas antes de escribir cualquier paso.
Los datos de entrada son la información con la que arranca el algoritmo: los números, textos o valores que llegan desde afuera y sobre los que se va a trabajar.
El dato de salida es el resultado que el enunciado pide, dicho de forma explícita ("cuánto paga", "cuántos minutos hacen falta") o deducible de la pregunta que cierra el enunciado.
Las restricciones son condiciones que el resultado tiene que respetar aunque no aparezcan como un dato más: cómo se tiene que expresar ese resultado, qué unidad usar, qué caso hay que contemplar. Una restricción no entra al cálculo como un número, pero cambia el algoritmo tanto como uno.
Separar esas tres cosas deja afuera, casi siempre, una cuarta categoría: el ruido. Es la información que el enunciado menciona -a veces porque describe la situación, a veces porque imita cómo se cuenta un problema en la vida real- pero que ningún paso del algoritmo necesita. Un enunciado bien leído es, en el fondo, un enunciado del que se sabe qué descartar.
La parte difícil no es detectar el ruido evidente, como un color o un dato decorativo. Es que una restricción real puede estar escrita con el mismo tono casual que el ruido, en la misma oración, sin ningún aviso de que ahí hay algo que el algoritmo no puede pasar por alto. Confundir una restricción con ruido produce un algoritmo que corre sin errores y devuelve un resultado prolijo, y que sin embargo no resuelve el problema que pedía el enunciado. Ese error es más caro que un error de sintaxis, porque nada avisa que ocurrió.
El siguiente enunciado mezcla las cuatro categorías a propósito.
Un tanque de agua, ubicado en el techo de un edificio y pintado de color celeste, tiene capacidad para 500 litros. Actualmente contiene 322 litros. Una canilla lo llena a razón de 15 litros por minuto. El portero revisa el tanque una vez por semana. ¿Cuántos minutos enteros, como mínimo, hacen falta para que quede lleno?
Antes de calcular nada, conviene ordenar lo que dice el enunciado en cuatro columnas:
entrada: capacidad total (500), litros actuales (322), litros por minuto (15)
salida: minutos enteros, como mínimo
restriccion: el resultado se expresa redondeado hacia arriba (un minuto incompleto
cuenta como un minuto entero)
ruido: el color del tanque, su ubicación, la frecuencia con que lo revisa el porteroNinguno de los tres datos de ruido participa del cálculo: se puede cambiar el color del tanque o mudarlo de edificio y el resultado no cambia. La restricción, en cambio, sí lo cambia: si se ignora "como mínimo" y se calcula el promedio exacto, sale un número con fracción de minuto que no responde la pregunta.
Con las cuatro columnas resueltas, escribir el algoritmo es directo:
algoritmo minutos_para_llenar(capacidad, litros_actuales, litros_por_minuto):
restar litros_actuales a capacidad para obtener los litros que faltan
dividir los litros que faltan por litros_por_minuto
redondear ese resultado hacia arriba
devolver el resultadoCon los números del enunciado, faltan 178 litros, que a 15 litros por minuto dan 11,87 minutos. Redondeado hacia arriba, el resultado es 12. Si el enunciado hubiera preguntado "cuántos minutos hacen falta en promedio" en lugar de "como mínimo", el paso de redondear sobraría y la respuesta sería 11,87: la misma cuenta, con una palabra distinta en la pregunta, pide un algoritmo distinto.
Analizar el siguiente enunciado, separar datos de entrada, dato de salida y restricciones, y descartar el ruido, antes de escribir el algoritmo.
Una fotocopiadora imprime 40 páginas por minuto. El papel del documento es tamaño A4 y viene grapado en packs de 500 hojas. Hace falta fotocopiar un documento de 1300 páginas. ¿Cuántos minutos, como mínimo, toma imprimir el documento completo?
Pista: antes de calcular nada, separar en cuatro columnas qué dato es la entrada, cuál es la salida esperada, y qué frase del enunciado impone una condición sobre cómo se expresa el resultado. Después preguntarse, dato por dato: ¿participa este número o esta palabra del cálculo, o solo describe la situación?
entrada: paginas totales (1300), paginas por minuto (40)
salida: minutos, como mínimo
restriccion: el resultado se redondea hacia arriba
ruido: el tamaño del papel (A4), que venga grapado, el tamaño de los packs (500)
algoritmo minutos_para_imprimir(paginas_totales, paginas_por_minuto):
dividir paginas_totales por paginas_por_minuto
redondear ese resultado hacia arriba
devolver el resultadoEl tamaño del papel y el packaging suenan a datos técnicos, pero ninguno de los dos entra en la cuenta: la fotocopiadora imprime a la misma velocidad sin importar en qué packs venía el papel. 1300 dividido 40 da 32,5, y redondeado hacia arriba, 33 minutos.
En una cena entre amigos, la cuenta total ascendió a $48000. El restaurante, conocido por su ambiente tranquilo y sus mesas al aire libre, sugiere una propina del 10%. La cuenta se divide en partes iguales entre 6 personas. ¿Cuánto tiene que pagar cada persona, propina incluida?
Pista: no toda frase que suena a comentario de color es ruido. Conviene revisar cada oración por separado, incluso las que describen el lugar, y preguntarse si algún número o condición quedó mencionado adentro sin que la redacción lo destaque como dato.
entrada: total de la cuenta (48000), porcentaje de propina (10), cantidad de
personas (6)
salida: monto que paga cada persona, propina incluida
restriccion: ninguna más allá de la división en partes iguales
ruido: el ambiente del restaurante, que tenga mesas al aire libre
algoritmo pago_por_persona(total_cuenta, porcentaje_propina, cantidad_personas):
dividir porcentaje_propina por 100
multiplicar total_cuenta por ese resultado para obtener la propina
sumar la propina a total_cuenta para obtener el total con propina
dividir el total con propina por cantidad_personas
devolver el resultadoEl porcentaje de propina está escrito como si fuera parte de la descripción del restaurante ("sugiere una propina del 10%"), en la misma oración que el ambiente tranquilo y las mesas al aire libre. Solo uno de esos tres datos entra al cálculo, y es el que menos parece un dato. Con los números del enunciado, la propina es $4800, el total con propina $52800, y cada persona paga $8800.
Antes de escribir el primer paso de un algoritmo hace falta separar qué datos llegan, qué resultado se espera y qué condiciones hay que respetar aunque no se pidan como un dato explícito. Lo que sobra en el enunciado no participa del algoritmo, y confundir una cosa con otra -tomar ruido por dato, o pasar por alto una restricción disfrazada de comentario- produce un algoritmo que resuelve un problema distinto del que pedía el enunciado.
Los tres enunciados de este post, una vez leídos, se resolvían con una lista corta de pasos, uno detrás del otro. No siempre es tan directo: hay problemas que, incluso después de identificar entrada, salida y restricciones, siguen siendo demasiado grandes para resolverse de un tirón. El próximo paso de la serie trata cómo partir un problema así en partes más chicas, cada una manejable por separado.