Random IRC quote :      <c0d3r> el prince of persiana

Soluciones al reto

Durante la última semana me han llegado varias soluciones al reto de la suma máxima en la lista de números. El primero en enviarla fue erg0t, que escribió este algoritmo en puro y duro C. Pero cansado de este lenguaje tan vulgar, sin glamour, y con tan poca clase (bastante que tiene structs), erg0t nos deleita con otra solución en el exclusivísimo e inescrutable Haskell.

import Data.List

f :: Integer -> Integer -> (Integer, Integer)

f 0 n | n < 0    = (0, n)
      | n >= 0  = (n, n)

f l n = let  a x = if x < 0  then 0 else x;
             b x = if x > l  then x else l
              in (a (l + n),b (l + n))

funcion :: [Integer] -> Integer

funcion lista = (\(x,y) -> maximum y) (mapAccumL f 0 lista)

He de decir que jamás había visto en mi vida ni una línea de código en Haskell, pero como buen jurado que soy he buscado un intérprete de Haskell, unos manuales en internet, y he comprobado que funciona. Incluso he llegado a entenderlo tras unas cuantas horas de investigación. Enhorabuena a erg0t por lo exótico de su solución.

También tenemos la solución de Miguel, que se va haciendo habitual, y que en realidad son dos soluciones: el algoritmo más obvio, de orden cuadrático, y el óptimo, de orden lineal. Además las explicaciones son abundantes y podemos disfrutar de esa notación húngara que delata sus orígenes Windowseros :).

Rodrigo Marcos nos ha envíado también su solución en Python, y yo mismo, después de que erg0t despertara mi interés por los lenguajes no imperativos, he programado mi solución en Prolog.

También quiero hacer una mención especial a Ángel Alonso que se curró una solución de última hora en Perl, pero no pudo terminar de ponerla a punto por falta de tiempo. Habrá más retos en el futuro para una revancha Ángel.

Y el que se lleva la estatuilla esta vez es… tara tatá tatá… erg0t! Por la solución más curiosa y eficiente al mismo tiempo.

6 Comentarios para “Soluciones al reto”

  1. Comment por erg0t | 08/13/07 at 1:33 am

    Me alegro que te gustara la solucion en Haskell, a mi la verdad no me gusto mucho como me quedo el codigo, asi que aqui posteo una version del algoritmo un poco mas parecida a la de C (y sin embargo el codigo se redujo mas aun).

    f :: (Integer, Integer) -> [Integer] -> Integer
    f (l, y) [] = y
    f (0, y) (x:xs) = f ((max x 0), (max x y)) xs
    f (l, y) (x:xs) = f ((max (l + x) 0), (max (l + x) y)) xs
    funcion :: [Integer] -> Integer
    funcion lista = f (0,(min (minimum lista) 0)) lista

    Lo de (min (minimum lista) 0) se puede remplazar por 0 si no nos importa que en el caso de que sean todos negativos retorne 0 en lugar del de mayor VA, sino tambien se puede reemplazar por algun negativo lo suficientemente chico. f es unas funcion recursiva pero el compilador de haskell seguramente lo convierte en un loop.

  2. Comment por Amian | 08/18/07 at 2:31 am

    Que buena chingada man

  3. Comment por Car\os | 09/11/07 at 1:44 pm

    Crítica a la solución lineal de miguel:

    «8) Sumamos la suma de los negativos a la suma de los positivos
    anteriores. Si es mayor o igual que 0, este subconjunto mejora
    la solucion, por lo que volvemos a 3. Si este subconjunto es
    menor que 0, este subconjunto empeoraria el siguiente sumatorio
    por lo que marcamos el comienzo del siguiente candidato en este
    punto y volvemos hasta 3»

    Cuando el subconjunto es menor que 0, no considera la posibilidad de que si se extiende más el rango, entonces el subconjunto pueda volver a ser mayor que 0 e incluso mayor que el calor anterior. Por lo tanto enta solución no es completa.

  4. Comment por Miguel | 09/17/07 at 5:24 pm

    Buenas tardes

    Gracias por el comentario, pero si he entendido bien la explicacion, me da la impresion de que te equivocas.
    La extension del rango por la izquierda esta contemplado en el propio algoritmo puesto que el calculo se va haciendo de izquierda a derecha. Por otro lado, si la extensión se da por la derecha, en caso de obtener un numero mayor que 0, siempre obtendriamos un numero menor que el que obtendriamos quitando la parte que el algoritmo considera descartable .
    Veo que te has fijado en el pequeño pseudo-codigo que añadi en el texto, en el que no se explica el algoritmo sistematicamente. Para hacerte una idea exacta del algoritmo fijate mejor en el codigo fuente.
    No veo claramente el caso de error que comentas para este algoritmo. Quizas con un contra-ejemplo lo puedas dejar mas claro

    Gracias por participar
    Y un saludo!

  5. Comment por Francisco Javier | 09/22/07 at 7:15 pm

    Hola!! me podeis resolver este problema, y enviarmelo a mi email: fran-23.jaja@hotmail.com

    ¿Sabes colocar los dígitos del 1 al 9 para obtener la fracción 1/3, sabiendo ke 6729/13458 es igual a 1/2?

  6. Comment por Car\os | 10/17/07 at 8:14 pm

    Me temo que tienes razón, Miguel. La solución es correcta.
    No me había fijado en que siempre se guarda el rango máximo encontrado…

Se han cerrado los comentarios