Máximo producto en la partición de un número
El artículo de esta semana de Antonio Roldán en su blog Números y hoja de cálculo es Máximo producto en la partición de un número (1)
Una partición de un entero positivo n es una forma de descomponer n como suma de enteros positivos. Dos sumas se considerarán iguales si solo difieren en el orden de los sumandos. Por ejemplo, las 11 particiones de 6 (con sus correspondientes productos) son
1 2 3 4 5 6 7 8 9 10 11 |
6 = 6 | 6 = 6 6 = 5 + 1 | 5 x 1 = 5 6 = 4 + 2 | 4 x 2 = 8 6 = 4 + 1 + 1 | 4 x 1 x 1 = 4 6 = 3 + 3 | 3 x 3 = 9 6 = 3 + 2 + 1 | 3 x 2 x 1 = 6 6 = 3 + 1 + 1 + 1 | 3 x 1 x 1 x 1 = 3 6 = 2 + 2 + 2 | 2 x 2 x 2 = 8 6 = 2 + 2 + 1 + 1 | 2 x 2 x 1 x 1 = 4 6 = 2 + 1 + 1 + 1 + 1 | 2 x 1 x 1 x 1 x 1 = 2 6 = 1 + 1 + 1 + 1 + 1 + 1 | 1 x 1 x 1 x 1 x 1 x 1 = 1 |
Se observa que el máximo producto de las particiones de 6 es 9.
Definir la función
1 |
maximoProductoParticiones :: Int -> Int |
tal que (maximoProductoParticiones n) es el máximo de los productos de las particiones de n. Por ejemplo,
1 2 3 4 5 6 7 8 9 10 |
maximoProductoParticiones 4 == 4 maximoProductoParticiones 5 == 6 maximoProductoParticiones 6 == 9 maximoProductoParticiones 7 == 12 maximoProductoParticiones 8 == 18 maximoProductoParticiones 9 == 27 maximoProductoParticiones 50 == 86093442 maximoProductoParticiones 100 == 7412080755407364 maximoProductoParticiones 200 == 61806308765265224723841283607058 length (show (maximoProductoParticiones (10^7))) == 1590405 |
Comprobar con QuickChek que los únicos posibles factores de (maximoProductoParticiones n) son 2 y 3.
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
import Data.List (genericIndex, sort) import Data.Numbers.Primes (primeFactors) import Test.QuickCheck -- 1ª definición -- ============= maximoProductoParticiones1 :: Integer -> Integer maximoProductoParticiones1 n = maximum [product xs | xs <- particiones1 n] -- (particiones1 n) es la lista de las particiones de n. Por ejemplo, -- λ> particiones1 4 -- [[4],[3,1],[2,2],[2,1,1],[1,1,1,1]] -- λ> particiones1 5 -- [[5],[4,1],[3,2],[3,1,1],[2,2,1],[2,1,1,1],[1,1,1,1,1]] particiones1 :: Integer -> [[Integer]] particiones1 0 = [[]] particiones1 n = [x:y | x <- [n,n-1..1] , y <- particiones1 (n-x) , [x] >= take 1 y] -- 2ª definición -- ============= maximoProductoParticiones2 :: Integer -> Integer maximoProductoParticiones2 n = maximum [product xs | xs <- particiones2 n] -- (particiones2 n) es la lista de las particiones de n. Por ejemplo, -- λ> particiones2 4 -- [[4],[3,1],[2,2],[2,1,1],[1,1,1,1]] -- λ> particiones2 5 -- [[5],[4,1],[3,2],[3,1,1],[2,2,1],[2,1,1,1],[1,1,1,1,1]] particiones2 :: Integer -> [[Integer]] particiones2 n = aux `genericIndex` n where aux = [] : map particiones [1..] where particiones n = [n] : [x:p | x <- [n,n-1..1] , p <- aux `genericIndex` (n-x) , x >= head p] -- 3ª definición -- ============= maximoProductoParticiones3 :: Integer -> Integer maximoProductoParticiones3 0 = 1 maximoProductoParticiones3 n = maximum [(n-i) * maximoProductoParticiones3 i | i <- [0..n-1]] -- 4ª definición -- ============= maximoProductoParticiones4 :: Integer -> Integer maximoProductoParticiones4 n = maximosProductosParticiones `genericIndex` n maximosProductosParticiones :: [Integer] maximosProductosParticiones = 1 : f [1] where f xs = y : f (y:xs) where y = maximum (zipWith (*) [1..] xs) -- 5ª definición -- ============= maximoProductoParticiones5 :: Integer -> Integer maximoProductoParticiones5 1 = 1 maximoProductoParticiones5 n | r == 0 = 3^q | r == 1 = 4 * 3^(q-1) | r == 2 = 2 * 3 ^q where (q,r) = quotRem n 3 -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> maximoProductoParticiones1 20 -- 1458 -- (5.42 secs, 832,283,184 bytes) -- λ> maximoProductoParticiones2 20 -- 1458 -- (0.02 secs, 0 bytes) -- λ> maximoProductoParticiones3 20 -- 1458 -- (3.18 secs, 524,500,000 bytes) -- λ> maximoProductoParticiones4 20 -- 1458 -- (0.00 secs, 0 bytes) -- -- λ> maximoProductoParticiones2 50 -- 86093442 -- (9.18 secs, 980,524,320 bytes) -- λ> maximoProductoParticiones4 50 -- 86093442 -- (0.01 secs, 1,381,192 bytes) -- λ> maximoProductoParticiones5 50 -- 86093442 -- (0.00 secs, 0 bytes) -- -- λ> length (show (maximoProductoParticiones4 2000)) -- 319 -- (2.93 secs, 638,270,872 bytes) -- λ> length (show (maximoProductoParticiones5 2000)) -- 319 -- (0.01 secs, 0 bytes) -- Comprobación -- ============ -- La propiedad es prop_factores :: Integer -> Property prop_factores n = n > 0 ==> primeFactors (maximoProductoParticiones5 n) `contenido` [2,3] contenido :: Eq a => [a] -> [a] -> Bool contenido xs ys = all (`elem` ys) xs -- La comprobación es -- λ> quickCheck prop_factores -- +++ OK, passed 100 tests. |
Referencia
- Máximo producto en la partición de un número (1) de Antonio Roldán en el blog Números y hoja de cálculo.
- Sucesión A000792 de la OEIS.
Para chequear la propiedad:
Suponiendo que la propiedad es cierta, podemos escribir la función de forma muy simple:
Para optimizar, evitamos la recursión.
Mas simplificado:
La propiedad se ve de forma intuitiva fácilmente. Nuestro objetivo es conseguir el máximo producto a partir de las particiones de n, dividimos a n en n veces el número 1 y tenemos que agruparlos de forma que nos dé el máximo producto, para ello queremos el máximo número de factores lo más grande posible, el factor óptimo será 3. Podemos ver que para todo entero n mayor que 4 su máximo producto es mayor que n. Por tanto si vemos los casos para n < 6 los otros se reducen a estos, ya que si agrupamos los 1 como queramos, de forma que no quede ningún 1 suelto, si alguno es más grande que 4 aplicamos máximoProducto en ese factor. Si n=5 (n=2 mod 3) el máximo producto es 3×2, si n=4 (n=1 mod 3) el máximo producto es 2×2 y si n=3 (n=0 mod 3) el máximo producto es 3. Generalizando para el caso n > 6 obtenemos el resultado de arriba.