Acciones

Parcial 1 Sol

De Informática de 1º de Matemáticas [Curso 2021-22, Grupo 2]

-- -----------------------------------------------------------------------------
-- Informática de 1º de Grado en Matemáticas. Grupo 2.
-- Examen 1 de evaluación alternativa (12 de noviembre 2021).
-- -----------------------------------------------------------------------------

import Test.QuickCheck
import Data.Char

-- -----------------------------------------------------------------------------
-- Ejercicio 1.1. Un número imparitario es aquel que tiene una cantidad impar
-- de cifras pares y una cantidad par de cifras impares. Por ejemplo, 235 es
-- imparitario porque tiene 1 par (el 2) y 2 impares (el 3 y 5). De igual forma,
-- 101, 103, 105, 107, 291, 14238 y 1106871 son imparitarios, mientras que 21,
-- 2468 y 11258 no lo son.
--
-- Define la función (numeroImparitario n), tal que indique si un número n
-- es imparitario. Por ejemplo,
--   λ> numeroImparitario 103      == True
--   λ> numeroImparitario 291      == True
--   λ> numeroImparitario 1106871  == True
--   λ> numeroImparitario 21       == False
--   λ> numeroImparitario 2468     == False
--   λ> numeroImparitario 11358    == True
--   λ> numeroImparitario 11258    == False
-- -----------------------------------------------------------------------------

numeroImparitario :: Integer -> Bool
numeroImparitario n = odd p && even i
  where cs = show n
        p = sum [1 | c <- cs, elem c "02468"]
        i = sum [1 | c <- cs, elem c "13579"]

cifras :: Integer -> [Int]
cifras x = [read [c] | c <- show x]

numeroImparitario' :: Integer -> Bool
numeroImparitario' n = odd p && even i
  where cs = cifras n
        p = sum [1 | c <- cs, even c]
        i = sum [1 | c <- cs, odd c]

-- -----------------------------------------------------------------------------
-- Ejercicio 1.2. Comprueba con QuickCheck que si n es un número positivo
-- de más de tres cifras e imparitario, m también es imparitario, donde
-- m es n+3, si la última cifra de n es 8 o 9, o n+2, en otro caso. Por ejemplo,
-- son imparitarios 291 y 291+2=293, 299 y 299+3=301, y 358 y 358+3=361.
-- -----------------------------------------------------------------------------

prop_imparitario :: Integer -> Property
prop_imparitario x = numeroImparitario n ==> numeroImparitario n'
  where n' = if rem n 10 == 9 || rem n 10 == 8 then n+3 else n+2
        n = 100 + abs x

-- -----------------------------------------------------------------------------

-- -----------------------------------------------------------------------------
-- Ejercicio 2. Representaremos la agenda de nuestras asignaturas como sigue:
-- una lista de tuplas con primera componente el nombre abreviado de la
-- asignatura, y segunda componente una lista de ternas, donde cada
-- terna indica un día y un rago de horario representado como un entero (por
-- ejemplo, 900 es 9:00, 1130 es 11:30, etc.)

agenda :: [(String,[(String,Int,Int)])]
agenda = [ ("Inf",[("Mie",900,1100),("Vie",900,1100)]),
           ("Alg",[("Mie",1130,1330),("Ju",1130,1330)]),
           ("Fis",[("Lu",900,1100),("Mar",900,1100)]),
           ("Cal",[("Lu",1130,1330),("Ju",900,1100)]),
           ("Est",[("Mar",1130,1330),("Vie",900,1100)]) ]

-- Define la función (asignatura ds h as), tal que devuelva la lista de
-- asignaturas donde debemos estar el día ds a las h horas, según la agenda
-- as. Si estamos en el descanso o no hay asignaturas, devolver la lista
-- vacía. El nombre abreviado del día a buscar no debe diferenciar entre
-- minúsculas y mayúsculas (es decir, "lu" es igual que "Lu"). Por ejemplo,
--    λ> asignatura "Lu" 930 agenda
--       ["Fis"]
--    λ> asignatura "lu" 945 agenda
--       ["Fis"]
--    λ> asignatura "Vie" 930 agenda
--       ["Inf","Est"]
--    λ> asignatura "Mar" 1115 agenda
--       []
-- -----------------------------------------------------------------------------

asignatura :: String -> Int -> [(String,[(String,Int,Int)])] -> [String]
asignatura ds h as = [ ns | (ns,hs) <- as, (ds',h1,h2) <- hs, (minusculas ds') == (minusculas ds), h1 <= h, h2 >= h ]
  where minusculas xs = [toLower x | x <- xs]

-- -----------------------------------------------------------------------------

-- -----------------------------------------------------------------------------
-- Ejercicio 3. Dos vectores son más compatibles cuanto mayor sea su producto
-- escalar (hasta llegar a ser paralelos). Representaremos los vectores como
-- listas de números. Define la función (masCompatibles xs yss), tal que dado
-- un vector xs y una lista de vectores yss, devuelva la lista de los vectores
-- más compatibles de yss respecto de xs. Por ejemplo
--   λ> masCompatibles [1,0,1] [[0,1,0], [2,3,1], [-1,7,1],[3,1,0]]
--      [[2,3,1],[3,1,0]]
--   λ> masCompatibles [1,0,1] [[0,1,0], [2,3,1], [-1,7,1],[4,-1,4]]
--      [[4,-1,4]]
-- -----------------------------------------------------------------------------

masCompatibles :: (Ord a,Num a) => [a] -> [[a]] -> [[a]]
masCompatibles xs yss = [ys | ys <-yss, productoEscalar xs ys == m]
  where m = maximum productos
        productos = [productoEscalar xs ys | ys <- yss]
        productoEscalar xs ys = sum [x*y | (x,y) <- zip xs ys]

-- -----------------------------------------------------------------------------

-- -----------------------------------------------------------------------------
-- Ejercicio 4.1 Definir, por comprensión, la función (coincidenciasC k xs ys),
-- tal que verifique si las listas xs e ys coinciden en, al menos, k de sus
-- posiciones. Por ejemplo,
--    λ> coincidenciasC 7 "salamanca" "salamandra"  ==  True
--    λ> coincidenciasC 2 [1,2,3,4,5] [1,3,3,8,1]   ==  True
--    λ> coincidenciasC 4 "almendra" "almazara"     ==  True
--    λ> coincidenciasC 6 "almendra" "almazara"     ==  False
-- -----------------------------------------------------------------------------

coincidenciasC :: Eq a => Int -> [a] -> [a] -> Bool
coincidenciasC n xs ys = sum [1 | (x,y) <- zip xs ys, x==y] >= n

-- -----------------------------------------------------------------------------
-- Ejercicio 4.2 Definir, por recursión, la función (coincidencias k xs ys),
-- tal que verifique si las listas xs e ys coinciden en, al menos, k de sus
-- posiciones. Por ejemplo,
--    λ> coincidenciasR 7 "salamanca" "salamandra"  ==  True
--    λ> coincidenciasR 2 [1,2,3,4,5] [1,3,3,8,1]   ==  True
--    λ> coincidenciasR 4 "almendra" "almazara"     ==  True
--    λ> coincidenciasR 6 "almendra" "almazara"     ==  False
-- -----------------------------------------------------------------------------

coincidenciasR :: Eq a => Int -> [a] -> [a] -> Bool
coincidenciasR 0 _ _                       = True
coincidenciasR n [] _                      = False
coincidenciasR n _ []                      = False
coincidenciasR n (x:xs) (y:ys) | x == y    = coincidenciasR (n-1) xs ys
                               | otherwise = coincidenciasR n xs ys

-- -----------------------------------------------------------------------------