{"id":8534,"date":"2024-04-09T06:00:50","date_gmt":"2024-04-09T04:00:50","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/?p=8534"},"modified":"2024-04-16T18:54:36","modified_gmt":"2024-04-16T16:54:36","slug":"09-abr-24","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/09-abr-24\/","title":{"rendered":"M\u00e1xima suma de caminos en un tri\u00e1ngulo"},"content":{"rendered":"<p>Los tri\u00e1ngulos se pueden representar mediante listas de listas. Por ejemplo, el tri\u00e1ngulo<\/p>\n<pre lang=\"haskell\">\n      3\n     7 4\n    2 4 6\n   8 5 9 3\n<\/pre>\n<p>se representa por<\/p>\n<pre lang=\"haskell\">\n   [[3],[7,4],[2,4,6],[8,5,9,3]]\n<\/pre>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"haskell\">\n   maximaSuma :: [[Integer]] -> Integer\n<\/pre>\n<p>tal que (maximaSuma xss) es el m\u00e1ximo de las sumas de los  de los caminos en el tri\u00e1ngulo xss donde los caminos comienzan en el elemento de la primera fila, en cada paso se mueve a uno de  sus dos elementos adyacentes en la fila siguiente y terminan en la \u00faltima fila. Por ejemplo,<\/p>\n<pre lang=\"haskell\">\n   maximaSuma [[3],[7,4]]                    ==  10\n   maximaSuma [[3],[7,4],[2,4,6]]            ==  14\n   maximaSuma [[3],[7,4],[2,4,6],[8,5,9,3]]  ==  23\n   maximaSuma [[n..n+n] | n <- [0..100]]     ==  10100\n   maximaSuma [[n..n+n] | n <- [0..1000]]    ==  1001000\n   maximaSuma [[n..n+n] | n <- [0..2000]]    ==  4002000\n   maximaSuma [[n..n+n] | n <- [0..3000]]    ==  9003000\n   maximaSuma [[n..n+n] | n <- [0..4000]]    ==  16004000\n<\/pre>\n<p><!--more--><\/p>\n<p><a name=\"haskell\"><\/a><\/p>\n<h2>1. Soluciones en Haskell<\/h2>\n<pre lang=\"haskell\">\nmodule Maxima_suma_de_caminos_en_un_triangulo where\n\nimport Data.List (tails)\nimport Test.Hspec (Spec, describe, hspec, it, shouldBe)\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma1 :: [[Integer]] -> Integer\nmaximaSuma1 xss =\n  maximum [sum ys | ys <- caminos xss]\n\ncaminos :: [[Integer]] -> [[Integer]]\ncaminos []    = [[]]\ncaminos [[x]] = [[x]]\ncaminos ([x]:[y1,y2]:zs) =\n  [x:y1:us | (_:us) <- caminos ([y1] : map init zs)] ++\n  [x:y2:vs | (_:vs) <- caminos ([y2] : map tail zs)]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma2 :: [[Integer]] -> Integer\nmaximaSuma2 xss = maximum (map sum (caminos xss))\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma3 :: [[Integer]] -> Integer\nmaximaSuma3 = maximum . map sum . caminos\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma4 :: [[Integer]] -> Integer\nmaximaSuma4 []    = 0\nmaximaSuma4 [[x]] = x\nmaximaSuma4 ([x]:[y1,y2]:zs) =\n  x + max (maximaSuma4 ([y1] : map init zs))\n          (maximaSuma4 ([y2] : map tail zs))\n\n-- 5\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma5 :: [[Integer]] -> Integer\nmaximaSuma5 xss = head (foldr1 g xss)\n  where\n    f x y z = x + max y z\n    g xs ys = zipWith3 f xs ys (tail ys)\n\n-- 6\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma6 :: [[Integer]] -> Integer\nmaximaSuma6 xss = head (foldr1 aux xss)\n  where aux a b = zipWith (+) a (zipWith max b (tail b))\n\n-- 7\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma7 :: [[Integer]] -> Integer\nmaximaSuma7 xss = head (foldr (flip f) (last xss) (init xss))\n  where f = zipWith ((+) . maximum . take 2) . tails\n\n-- 8\u00aa soluci\u00f3n\n-- ===========\n\nmaximaSuma8 :: [[Integer]] -> Integer\nmaximaSuma8 = head . foldr1 aux\n  where\n    aux [] _              = []\n    aux (x:xs) (y0:y1:ys) = x + max y0 y1 : aux xs (y1:ys)\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- Para la comparaciones se usar\u00e1 la siguiente funci\u00f3n que construye un\n-- tri\u00e1ngulo de la altura dada. Por ejemplo,\n--    triangulo 2  ==  [[0],[1,2]]\n--    triangulo 3  ==  [[0],[1,2],[2,3,4]]\n--    triangulo 4  ==  [[0],[1,2],[2,3,4],[3,4,5,6]]\ntriangulo :: Integer -> [[Integer]]\ntriangulo n = [[k..k+k] | k <- [0..n-1]]\n\n-- La comparaci\u00f3n es\n--    (1.97 secs, 876,483,056 bytes)\n--    \u03bb> maximaSuma1 (triangulo 19)\n--    342\n--    (2.37 secs, 1,833,637,824 bytes)\n--    \u03bb> maximaSuma2 (triangulo 19)\n--    342\n--    (2.55 secs, 1,804,276,472 bytes)\n--    \u03bb> maximaSuma3 (triangulo 19)\n--    342\n--    (2.57 secs, 1,804,275,320 bytes)\n--    \u03bb> maximaSuma4 (triangulo 19)\n--    342\n--    (0.28 secs, 245,469,384 bytes)\n--    \u03bb> maximaSuma5 (triangulo 19)\n--    342\n--    (0.01 secs, 153,272 bytes)\n--    \u03bb> maximaSuma6 (triangulo 19)\n--    342\n--    (0.01 secs, 161,360 bytes)\n--    \u03bb> maximaSuma7 (triangulo 19)\n--    342\n--    (0.01 secs, 187,456 bytes)\n--    \u03bb> maximaSuma8 (triangulo 19)\n--    342\n--    (0.01 secs, 191,160 bytes)\n--\n--    \u03bb> maximaSuma4 (triangulo 22)\n--    462\n--    (2.30 secs, 1,963,037,888 bytes)\n--    \u03bb> maximaSuma5 (triangulo 22)\n--    462\n--    (0.00 secs, 173,512 bytes)\n--    \u03bb> maximaSuma6 (triangulo 22)\n--    462\n--    (0.01 secs, 182,904 bytes)\n--    \u03bb> maximaSuma7 (triangulo 22)\n--    462\n--    (0.01 secs, 216,560 bytes)\n--    \u03bb> maximaSuma8 (triangulo 22)\n--    462\n--    (0.01 secs, 224,160 bytes)\n--\n--    \u03bb> maximaSuma5 (triangulo 3000)\n--    8997000\n--    (2.25 secs, 2,059,784,792 bytes)\n--    \u03bb> maximaSuma6 (triangulo 3000)\n--    8997000\n--    (2.15 secs, 2,404,239,896 bytes)\n--    \u03bb> maximaSuma7 (triangulo 3000)\n--    8997000\n--    (1.53 secs, 2,612,659,504 bytes)\n--    \u03bb> maximaSuma8 (triangulo 3000)\n--    8997000\n--    (3.47 secs, 3,520,910,256 bytes)\n--\n--    \u03bb> maximaSuma7 (triangulo 4000)\n--    15996000\n--    (3.12 secs, 4,634,841,200 bytes)\n\n-- Verificaci\u00f3n\n-- ============\n\nverifica :: IO ()\nverifica = hspec spec\n\nspecG :: ([[Integer]] -> Integer) -> Spec\nspecG maximaSuma = do\n  it \"e1\" $\n    maximaSuma [[3],[7,4]]                    `shouldBe`  10\n  it \"e2\" $\n    maximaSuma [[3],[7,4],[2,4,6]]            `shouldBe`  14\n  it \"e3\" $\n    maximaSuma [[3],[7,4],[2,4,6],[8,5,9,3]]  `shouldBe`  23\n\nspec :: Spec\nspec = do\n  describe \"def. 1\" $ specG maximaSuma1\n  describe \"def. 2\" $ specG maximaSuma2\n  describe \"def. 3\" $ specG maximaSuma3\n  describe \"def. 4\" $ specG maximaSuma4\n  describe \"def. 5\" $ specG maximaSuma5\n  describe \"def. 6\" $ specG maximaSuma6\n  describe \"def. 7\" $ specG maximaSuma7\n  describe \"def. 8\" $ specG maximaSuma8\n\n-- La verificaci\u00f3n es\n--    \u03bb> verifica\n--    Finished in 0.0053 seconds\n--    24 examples, 0 failures\n<\/pre>\n<p><a name=\"python\"><\/a><\/p>\n<h2>2. Soluciones en Python<\/h2>\n<pre lang=\"python\">\nfrom timeit import Timer, default_timer\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef caminos(xss: list[list[int]]) -> list[list[int]]:\n    if not xss:\n        return [[]]\n    if len(xss) == 1:\n        return xss\n    x = xss[0][0]\n    y1 = xss[1][0]\n    y2 = xss[1][1]\n    zss = xss[2:]\n    return [[x, y1] + us for _, *us in caminos([[y1]] + [zs[:-1] for zs in zss])] + \\\n           [[x, y2] + us for _, *us in caminos([[y2]] + [zs[1:] for zs in zss])]\n\n# maximaSuma1 :: [[Integer]] -> Integer\ndef maximaSuma1(xss: list[list[int]]) -> int:\n    return max((sum(ys) for ys in caminos(xss)))\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef maximaSuma2(xss: list[list[int]]) -> int:\n    if not xss:\n        return 0\n    if len(xss) == 1:\n        return xss[0][0]\n    x = xss[0][0]\n    y1 = xss[1][0]\n    y2 = xss[1][1]\n    zss = xss[2:]\n    return x + max(maximaSuma2([[y1]] + [us[:-1] for us in zss]),\n                   maximaSuma2([[y2]] + [us[1:] for us in zss]))\n\n# Verificaci\u00f3n\n# ============\n\ndef test_maximaSuma() -> None:\n    for maximaSuma in [maximaSuma1, maximaSuma2]:\n        assert maximaSuma([[3],[7,4]]) == 10\n        assert maximaSuma([[3],[7,4],[2,4,6]]) == 14\n        assert maximaSuma([[3],[7,4],[2,4,6],[8,5,9,3]]) == 23\n    print(\"Verificado\")\n\n# La verificaci\u00f3n es\n#    >>> test_maximaSuma()\n#    Verificado\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\n# Para la comparaciones se usar\u00e1 la siguiente funci\u00f3n que construye un\n# tri\u00e1ngulo de la altura dada. Por ejemplo,\n#    >>> triangulo(2)\n#    [[0], [1, 2]]\n#    >>> triangulo(3)\n#    [[0], [1, 2], [2, 3, 4]]\n#    >>> triangulo(4)\n#    [[0], [1, 2], [2, 3, 4], [3, 4, 5, 6]]\ndef triangulo(n: int) -> list[list[int]]:\n    return [list(range(k, k+k+1)) for k in range(n)]\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('maximaSuma1(triangulo(20))')\n#    3.21 segundos\n#    >>> tiempo('maximaSuma2(triangulo(20))')\n#    0.59 segundos\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Los tri\u00e1ngulos se pueden representar mediante listas de listas. Por ejemplo, el tri\u00e1ngulo 3 7 4 2 4 6 8 5 9 3 se representa por [[3],[7,4],[2,4,6],[8,5,9,3]] Definir la funci\u00f3n maximaSuma :: [[Integer]] -> Integer tal que (maximaSuma xss) es el m\u00e1ximo de las sumas de los de los caminos en el tri\u00e1ngulo xss donde&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"default","_kad_post_title":"default","_kad_post_layout":"default","_kad_post_sidebar_id":"","_kad_post_content_style":"default","_kad_post_vertical_padding":"default","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[581],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8534"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/comments?post=8534"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8534\/revisions"}],"predecessor-version":[{"id":8535,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/8534\/revisions\/8535"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/media?parent=8534"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/categories?post=8534"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/tags?post=8534"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}