Ir al contenido principal

Fracciones cancelativas

Una fracción x/y es cancelativa si se cumplen las siguientes condiciones:

  • x/y es propia (es decir, x < y),
  • ninguno de los números x e y son múltiplos de 10 y
  • existe un dígito d tal que al borrar una ocurrencia de d en x y otra en y se obtiene una fracción cuyo valor coincide con x/y.

Por ejemplo, 16/64 es cancelativa ya que borrando el 6 en el numerador y el denominador se obtiene 1/4 que es igual a la original: 16/64 = 1/4.

Definir la función

cancelativas :: Int -> Int -> [((Int, Int), (Int, Int))]

tal que (cancelativas m n) es la lista de las fracciones cancelativas con su denominador entre m y n. Por ejemplo,

λ> cancelativas 1 100
[((16,64),(1,4)),((26,65),(2,5)),((19,95),(1,5)),((49,98),(4,8))]
λ> cancelativas 101 150
[((22,121),(2,11)),((33,132),(3,12)),((34,136),(4,16)),((44,143),(4,13))]
λ> length (cancelativas 1 200)
18

Soluciones

import Data.List (intersect, nub)

cancelativas :: Int -> Int -> [((Int, Int), (Int, Int))]
cancelativas m n =
    nub [((x,y),(a,b))
         | y <- [m..n],
           y `mod` 10 /= 0,
           x <- [1..y-1],
           x `mod` 10 /= 0,
           (as,bs) <- reducciones (show x) (show y),
           not (null as),
           not (null bs),
           let (a,b) = (read as, read bs),
           b /= 0,
           a*y == b*x]

-- (reducciones xs ys) es la lista de los pares obtenidos eliminando una
-- ocurrencia de un elemento de xs tanto en xs como en ys. Por ejemplo,
--    λ> reducciones "abac" "bcba"
--    [("bac","bcb"),("abc","bcb"),
--     ("aac","cba"),("aac","bca"),
--     ("aba","bba")]
reducciones :: Eq a => [a] -> [a] -> [([a],[a])]
reducciones xs ys =
    concat [[(us,vs) | us <- eliminaciones xs x, vs <- eliminaciones ys x]
            | x <- nub (intersect xs ys)]

-- (eliminaciones xs y) es la lista de las listas obtenidas eliminando
-- una ocurrencia del elemento y en la lista xs. Por ejemplo,
--    eliminaciones "abacda" 'a'  ==  ["bacda","abcda","abacd"]
--    eliminaciones "abacd"  'a'  ==  ["bacd","abcd"]
--    eliminaciones "abacd"  'b'  ==  ["aacd"]
--    eliminaciones "abacd"  'e'  ==  []
eliminaciones :: Eq a => [a] -> a -> [[a]]
eliminaciones [] _ = []
eliminaciones (x:xs) y
    | x == y    = xs : [x:zs | zs <- zss]
    | otherwise = [x:zs | zs <- zss]
    where zss = eliminaciones xs y