Sumas con sumandos distintos o con sumandos impares
El número 6 se puede descomponer de 4 formas distintas como suma con sumandos distintos:
| 1 2 3 4 |    6 = 1 + 2 + 3    6 = 1 + 5    6 = 2 + 4    6 = 6 | 
y también se puede descomponer de 4 formas distintas como suma con sumandos impares:
| 1 2 3 4 |    6 = 1 + 1 + 1 + 1 + 1 + 1    6 = 1 + 1 + 1 + 3    6 = 1 + 5    6 = 3 + 3 | 
Definir las siguientes funciones
| 1 2 3 4 5 |    sumasSumandosDistintos  :: Integer -> [[Integer]]    nSumasSumandosDistintos :: Integer -> Int    sumasSumandosImpares    :: Integer -> [[Integer]]    nSumasSumandosImpares   :: Integer -> Int    igualdadDeSumas         :: Integer -> Bool | 
tales que
- (sumasSumandosDistintos n) es la lista de las descomposiciones de n como sumas con sumandos distintos. Por ejemplo,
| 1 2 |      sumasSumandosDistintos 5  ==  [[1,4],[2,3],[5]]      sumasSumandosDistintos 6  ==  [[1,2,3],[1,5],[2,4],[6]] | 
- (nSumasSumandosDistintos n) es el número de descomposiciones de n como sumas con sumandos distintos. Por ejemplo,
| 1 2 |      nSumasSumandosDistintos 6  ==  4      nSumasSumandosDistintos 7  ==  5 | 
- (sumasSumandosImpares n) es la lista de las descomposiones de n como sumas con sumandos impares. Por ejemplo,
| 1 2 |      sumasSumandosImpares 5  ==  [[1,1,1,1,1],[1,1,3],[5]]      sumasSumandosImpares 6  ==  [[1,1,1,1,1,1],[1,1,1,3],[1,5],[3,3]] | 
- (nSumasSumandosImpares n) es el número de descomposiciones de n como sumas con sumandos impares. Por ejemplo,
| 1 2 |      nSumasSumandosImpares 6  ==  4      nSumasSumandosImpares 7  ==  5 | 
- (igualdadDeSumas n) se verifica si, para todo k entre 1 y n, las funciones nSumasSumandosDistintos y nSumasSumandosImpares son iguales. Por ejemplo,
| 1 |      igualdadDeSumas 40  ==  True | 
Soluciones
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import Data.List (delete, nub) -- Definiciones de sumasSumandosDistintos -- ====================================== -- 1ª definición sumasSumandosDistintos sumasSumandosDistintos :: Integer -> [[Integer]] sumasSumandosDistintos n = aux n [1..n]   where aux 0 _ = [[]]         aux _ [] = []         aux x ys@(y:_)           | x < y     = []           | x == y    = [[x]]           | otherwise = [z : zs | z <- ys                                 , zs <- aux (x - z) (dropWhile (<=z) ys)] -- 2ª definición de sumasSumandosDistintos sumasSumandosDistintos2 :: Integer ->[[Integer]] sumasSumandosDistintos2 = aux 0   where aux i z           | z < 0  = []           | z == 0 = [[]]           | z > 0  = concat [map (j:) (aux j (z-j)) | j <- [i+1..z]] -- Definición de nSumasSumandosDistintos -- ===================================== nSumasSumandosDistintos :: Integer -> Int nSumasSumandosDistintos =   length . sumasSumandosDistintos -- Definiciones de sumasSumandosImpares -- ==================================== -- 1ª definición de sumasSumandosImpares sumasSumandosImpares :: Integer -> [[Integer]] sumasSumandosImpares n = aux n [1,3..n]   where aux n _ | n < 0 = []         aux 0 _  = [[]]         aux _ [] = []         aux x zs@(y:ys) = [y:zs | zs <- aux (x-y) zs] ++ aux x ys  -- 2ª definición de sumasSumandosImpares sumasSumandosImpares2 :: Integer ->[[Integer]] sumasSumandosImpares2 = aux 1   where aux i z           | z < 0  = []           | z == 0 = [[]]           | z > 0  = concat [map (j:) (aux j (z-j)) | j <-[i,i+2..z]] -- Definición de nSumasSumandosImpares -- =================================== nSumasSumandosImpares :: Integer -> Int nSumasSumandosImpares =   length . sumasSumandosImpares -- Definición conjunta (de josejuan) -- ================================= -- podemos definir una gran familia de generadores de la siguiente forma sumas :: Integer ->Integer ->Integer ->Integer ->Integer ->[[Integer]] sumas u a b k n = s u n where   s i z | z < 0 = []         | z == 0 = [[]]         | z > 0 = concat [map (j:) (s j (z - j)) | j <-[k*i+a,k*i+b..z]] -- así, si queremos los distintos sumasSumandosDistintos3 :: Integer ->[[Integer]] sumasSumandosDistintos3 = sumas 0 1 2 1 -- o queremos los impares repetidos sumasSumandosImpares3 :: Integer ->[[Integer]] sumasSumandosImpares3 = sumas 1 0 2 1 -- Igualdad de las sumas -- ===================== igualdadDeSumas :: Integer -> Bool igualdadDeSumas n =   and [nSumasSumandosDistintos k == nSumasSumandosImpares k | k <- [1..n]] -- Comparación de eficiencia -- ========================= --    λ> length (sumasSumandosDistintos2 70) --    29927 --    (0.57 secs, 374,604,848 bytes) --    λ> length (sumasSumandosDistintos3 70) --    29927 --    (0.57 secs, 352,658,200 bytes) --    λ> length (sumasSumandosImpares 70) --    29927 --    (8.87 secs, 5,221,638,688 bytes) --    λ> length (sumasSumandosImpares2 70) --    29927 --    (0.61 secs, 422,132,696 bytes) --    λ> length (sumasSumandosImpares3 70) --    29927 --    (0.56 secs, 412,289,336 bytes) |