Ir al contenido principal

Determinación de los elementos minimales

Definir la función

minimales :: Eq a => [[a]] -> [[a]]

tal que (minimales xss) es la lista de los elementos de xss que no están contenidos en otros elementos de xss. Por ejemplo,

minimales [[1,3],[2,3,1],[3,2,5]]        ==  [[2,3,1],[3,2,5]]
minimales [[1,3],[2,3,1],[3,2,5],[3,1]]  ==  [[2,3,1],[3,2,5]]

Soluciones

module ElementosMinimales where

import Data.List (nub, delete, (\\))
import Data.Set (isSubsetOf, fromList)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

minimales1 :: Eq a => [[a]] -> [[a]]
minimales1 xss =
  [xs | xs <- xss,
        null [ys | ys <- xss, subconjuntoPropio xs ys]]

-- (subconjuntoPropio xs ys) se verifica si xs es un subconjunto propio
-- de ys. Por ejemplo,
--    subconjuntoPropio [1,3] [3,1,3]    ==  False
--    subconjuntoPropio [1,3,1] [3,1,2]  ==  True
subconjuntoPropio :: Eq a => [a] -> [a] -> Bool
subconjuntoPropio xs ys = subconjuntoPropio' (nub xs) (nub ys)
  where
    subconjuntoPropio' _ [] = False
    subconjuntoPropio' [] _ = True
    subconjuntoPropio' (x:xs') ys' =
      x `elem` ys' && subconjuntoPropio xs' (delete x ys')

-- 2ª solución
-- ===========

minimales2 :: Eq a => [[a]] -> [[a]]
minimales2 xss = filter noTieneSubconjunto xss
  where
    noTieneSubconjunto xs = not (any (subconjuntoPropio xs) xss)

-- 3ª solución
-- ===========

minimales3 :: Eq a => [[a]] -> [[a]]
minimales3 xss =
  [xs | xs <- xss, all (not . subconjuntoPropio2 xs) xss]

subconjuntoPropio2 :: Eq a => [a] -> [a] -> Bool
subconjuntoPropio2 xs ys =
  xs' /= ys' && null (xs' \\ ys')
  where xs' = nub xs
        ys' = nub ys

-- 4ª solución
-- ===========

minimales4 :: Eq a => [[a]] -> [[a]]
minimales4 xss =
  [xs | xs <- xss, not (any (subconjuntoPropio2 xs) xss)]

-- 5ª solución
-- ===========

minimales5 :: Ord a => [[a]] -> [[a]]
minimales5 xss =
  [xs | xs <- xss, (not . any (subconjuntoPropio3 xs)) xss]

subconjuntoPropio3 :: Ord a => [a] -> [a] -> Bool
subconjuntoPropio3 xs ys =
  setXs /= setYs && setXs `isSubsetOf` setYs
  where setXs = fromList xs
        setYs = fromList ys

-- 6ª solución
-- ===========

minimales6 :: Eq a => [[a]] -> [[a]]
minimales6 = foldr agregarSiMinimal []
  where
    agregarSiMinimal xs yss
      | any (subconjuntoPropio xs) yss = yss
      | otherwise = xs : filter (not . flip subconjuntoPropio xs) yss

-- 7ª solución
-- ===========

minimales7 :: Eq a => [[a]] -> [[a]]
minimales7 xss =
  [xs | xs <- xss,
        not (or [subconjuntoPropio xs ys | ys <- xss])]

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: ([[Int]] -> [[Int]]) -> Spec
specG minimales = do
  it "e1" $
    minimales [[1,3],[2,3,1],[3,2,5]]        `shouldBe`  [[2,3,1],[3,2,5]]
  it "e2" $
    minimales [[1,3],[2,3,1],[3,2,5],[3,1]]  `shouldBe`  [[2,3,1],[3,2,5]]

spec :: Spec
spec = do
  describe "def. 1" $ specG minimales1
  describe "def. 2" $ specG minimales2
  describe "def. 3" $ specG minimales3
  describe "def. 4" $ specG minimales4
  describe "def. 5" $ specG minimales5
  describe "def. 6" $ specG minimales6
  describe "def. 7" $ specG minimales7

-- La verificación es
--    λ> verifica
--    14 examples, 0 failures

-- Equivalencia de las definiciones
-- ================================

-- La propiedad es
prop_minimales :: [[Int]] -> Bool
prop_minimales xss =
  all (== minimales1 xss)
      [minimales2 xss,
       minimales3 xss,
       minimales4 xss,
       minimales5 xss,
       minimales6 xss,
       minimales7 xss]

-- La comprobación es
--    λ> quickCheckWith (stdArgs {maxSize=40}) prop_minimales
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> length (minimales1 [[1..n] | n <- [1..100]])
--    1
--    (2.27 secs, 973,011,248 bytes)
--    λ> length (minimales2 [[1..n] | n <- [1..100]])
--    1
--    (2.19 secs, 973,170,440 bytes)
--    λ> length (minimales3 [[1..n] | n <- [1..100]])
--    1
--    (0.14 secs, 37,972,696 bytes)
--    λ> length (minimales4 [[1..n] | n <- [1..100]])
--    1
--    (0.12 secs, 37,804,728 bytes)
--    λ> length (minimales5 [[1..n] | n <- [1..100]])
--    1
--    (0.05 secs, 39,607,648 bytes)
--    λ> length (minimales6 [[1..n] | n <- [1..100]])
--    1
--    (0.12 secs, 36,018,976 bytes)
--    λ> length (minimales7 [[1..n] | n <- [1..100]])
--    1
--    (2.16 secs, 973,840,760 bytes)
--
--    λ> length (minimales3 [[1..n] | n <- [1..250]])
--    1
--    (3.47 secs, 533,688,496 bytes)
--    λ> length (minimales4 [[1..n] | n <- [1..250]])
--    1
--    (3.46 secs, 532,668,528 bytes)
--    λ> length (minimales5 [[1..n] | n <- [1..250]])
--    1
--    (0.27 secs, 579,544,232 bytes)
--    λ> length (minimales6 [[1..n] | n <- [1..250]])
--    1
--    (3.30 secs, 740,152,496 bytes)