import Data.Array
import qualified Data.Matrix as M
import Data.Maybe
import Data.List
import Test.QuickCheck
-- 1ª definición (Calculando todos los subconjuntos)
-- =================================================
subconjuntosSuma1 :: [Int] -> Int -> [[Int]]
subconjuntosSuma1 xs n =
[ys | ys <- subsequences xs, sum ys == n]
-- 2ª definición (por recursión)
-- =============================
subconjuntosSuma2 :: [Int] -> Int -> [[Int]]
subconjuntosSuma2 _ 0 = [[]]
subconjuntosSuma2 [] _ = []
subconjuntosSuma2 (x:xs) n
| n < x = subconjuntosSuma2 xs n
| otherwise = subconjuntosSuma2 xs n ++
[x:ys | ys <- subconjuntosSuma2 xs (n-x)]
-- 3ª definición (por programación dinámica)
-- =========================================
subconjuntosSuma3 :: [Int] -> Int -> [[Int]]
subconjuntosSuma3 xs n =
map reverse (matrizSubconjuntosSuma3 xs n ! (length xs,n))
-- (matrizSubconjuntosSuma3 xs m) es la matriz q tal que q(i,j) es la
-- lista de los subconjuntos de (take i xs) que suman j. Por ejemplo,
-- λ> elems (matrizSubconjuntosSuma3 [1,3,5] 9)
-- [[[]],[], [],[], [], [], [], [],[], [],
-- [[]],[[1]],[],[], [], [], [], [],[], [],
-- [[]],[[1]],[],[[3]],[[3,1]],[], [], [],[], [],
-- [[]],[[1]],[],[[3]],[[3,1]],[[5]],[[5,1]],[],[[5,3]],[[5,3,1]]]
-- Con las cabeceras,
-- 0 1 2 3 4 5 6 7 8 9
-- [] [[[]],[], [],[], [], [], [], [],[], [],
-- [1] [[]],[[1]],[],[], [], [], [], [],[], [],
-- [1,3] [[]],[[1]],[],[[3]],[[3,1]],[], [], [],[], [],
-- [1,3,5] [[]],[[1]],[],[[3]],[[3,1]],[[5]],[[5,1]],[],[[5,3]],[[5,3,1]]]
matrizSubconjuntosSuma3 :: [Int] -> Int -> Array (Int,Int) [[Int]]
matrizSubconjuntosSuma3 xs n = q
where m = length xs
v = listArray (1,m) xs
q = array ((0,0),(m,n)) [((i,j), f i j) | i <- [0..m],
j <- [0..n]]
f _ 0 = [[]]
f 0 _ = []
f i j | j < v ! i = q ! (i-1,j)
| otherwise = q ! (i-1,j) ++
[v!i:ys | ys <- q ! (i-1,j-v!i)]
-- 4ª definición (ordenando y por recursión)
-- =========================================
subconjuntosSuma4 :: [Int] -> Int -> [[Int]]
subconjuntosSuma4 xs = aux (sort xs)
where aux _ 0 = [[]]
aux [] _ = []
aux (y:ys) n
| y > n = []
| otherwise = aux ys n ++ [y:zs | zs <- aux ys (n-y)]
-- 5ª definición (ordenando y dinámica)
-- ====================================
subconjuntosSuma5 :: [Int] -> Int -> [[Int]]
subconjuntosSuma5 xs n =
matrizSubconjuntosSuma5 (reverse (sort xs)) n ! (length xs,n)
matrizSubconjuntosSuma5 :: [Int] -> Int -> Array (Int,Int) [[Int]]
matrizSubconjuntosSuma5 xs n = q
where m = length xs
v = listArray (1,m) xs
q = array ((0,0),(m,n)) [((i,j), f i j) | i <- [0..m],
j <- [0..n]]
f _ 0 = [[]]
f 0 _ = []
f i j | v ! i > j = []
| otherwise = q ! (i-1,j) ++
[v!i:ys | ys <- q ! (i-1,j-v!i)]
-- Equivalencia
-- ============
prop_subconjuntosSuma :: [Int] -> Int -> Bool
prop_subconjuntosSuma xs n =
all (`igual` subconjuntosSuma2 ys m) [ subconjuntosSuma3 ys m
, subconjuntosSuma4 ys m
, subconjuntosSuma5 ys m ]
where ys = map (\y -> 1 + abs y) xs
m = abs n
ordenado = sort . map sort
igual xss yss = ordenado xss == ordenado yss
-- La comprobación es
-- λ> quickCheck prop_subconjuntosSuma
-- +++ OK, passed 100 tests. |