Conjuntos de primos emparejables
Un conjunto de primos emparejables es un conjunto S de números primos tales que al concatenar cualquier par de elementos de S se obtiene un número primo. Por ejemplo, {3, 7, 109, 673} es un conjunto de primos emparejables ya que sus elementos son primos y las concatenaciones de sus parejas son 37, 3109, 3673, 73, 7109, 7673, 1093, 1097, 109673, 6733, 6737 y 673109 son primos.
Definir la función
1 |
emparejables :: Integer -> Integer -> [[Integer]] |
tal que (emparejables n m) es el conjunto de los conjuntos emparejables de n elementos menores que n. Por ejemplo,
1 2 3 4 5 6 |
take 5 (emparejables 2 10) == [[3,7]] take 5 (emparejables 3 10) == [] take 5 (emparejables 2 100) == [[3,7],[3,11],[3,17],[3,31],[3,37]] take 5 (emparejables 3 100) == [[3,37,67],[7,19,97]] take 5 (emparejables 4 100) == [] take 5 (emparejables 4 1000) == [[3,7,109,673],[23,311,677,827]] |
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 |
import Data.Numbers.Primes (primes, isPrime) import Data.List (nub, sort) import qualified Data.Set as S -- 1ª definición -- ============= emparejables :: Integer -> Integer -> [[Integer]] emparejables 0 _ = [[]] emparejables n m = nub [sort (x:xs) | x <- takeWhile (<=m) primes, xs <- xss, all (x `emparejable`) xs] where xss = emparejables (n-1) m emparejable :: Integer -> Integer -> Bool emparejable x y = isPrime (concatenacion x y) && isPrime (concatenacion y x) concatenacion :: Integer -> Integer -> Integer concatenacion x y = read (show x ++ show y) -- 2ª definición -- ============= emparejables2 :: Integer -> Integer -> [[Integer]] emparejables2 n m = map reverse (aux n m) where aux 1 m = [[x] | x <- takeWhile (<=m) primes] aux n m = [p:ys | ys@(x:xs) <- xss, p <- dropWhile (<x) ps, all (p `emparejable`) ys] where ps = takeWhile (<=m) primes xss = aux (n-1) m -- 3ª definición -- ============= emparejables3 :: Integer -> Integer -> [[Integer]] emparejables3 n m = map S.toList (aux n m) where aux 1 m = [S.singleton x | x <- takeWhile (<=m) primes] aux n m = [S.insert x xs | x <- takeWhile (<=m) primes, xs <- xss, all (x `emparejable`) xs] where xss = aux (n-1) m -- 2ª definición -- ============= emparejables4 :: Integer -> Integer -> [[Integer]] emparejables4 n m = map S.toList (aux n m) where aux 1 m = [S.singleton x | x <- takeWhile (<=m) primes] aux n m = [S.insert p ys | ys <- xss, let (x,xs) = S.deleteFindMax ys, p <- dropWhile (<x) ps, all (p `emparejable`) ys] where ps = takeWhile (<=m) primes xss = aux (n-1) m -- Comparación de eficiencia -- ========================= -- λ> head (emparejables 4 1000) -- [3,7,109,673] -- (20.36 secs, 11,781,891,120 bytes) -- -- λ> head (emparejables2 4 1000) -- [3,7,109,673] -- (0.02 secs, 0 bytes) -- -- λ> head (emparejables3 4 1000) -- [3,7,109,673] -- (38.04 secs, 21,542,334,024 bytes) -- -- λ> head (emparejables4 4 1000) -- [3,7,109,673] -- (0.03 secs, 0 bytes) |
No conozco ninguna propiedad que permita reducir el comparar todos con todos los primos, por lo que el coste es básicamente O(m^2), así, para m>100000 es impracticable, por lo que sólo sirve para n<6 y m<100000.
Generando progresivamente con un pelín de fuerza bruta