Acciones

Relación 4

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

-- I1M 2021-22: Rel_4.hs (27 de Octubre de 2021)
-- Definiciones por comprensión (II)
-- Departamento de Ciencias de la Computación e I.A.
-- Universidad de Sevilla
-- =====================================================================

-- ---------------------------------------------------------------------
-- Introducción                                                       --
-- ---------------------------------------------------------------------
--
-- En esta relación se presentan ejercicios con definiciones por
-- comprensión correspondientes al tema 5.
-- 
-- ---------------------------------------------------------------------
-- § Librerías auxiliares                                             --
-- ---------------------------------------------------------------------

import Test.QuickCheck

-- ---------------------------------------------------------------------
-- Ejercicio 1. Definir la función 
--    divisoresPrimos :: Int -> [Int]
-- tal que (divisoresPrimos x) es la lista de los divisores primos de x. 
-- Por ejemplo, 
--    divisoresPrimos 40  ==  [2,5]
--    divisoresPrimos 70  ==  [2,5,7]
-- ------------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sánchez Martín
divisores :: Int -> [Int]
divisores n = [x | x<-[1..n], mod n x == 0]
primo :: Int -> Bool
primo n = divisores n == [1,n]

divisoresPrimos :: Int -> [Int]
divisoresPrimos n = [ x | x <- divisores n, primo x]

-- Adolfo Sagrera Vivancos
divisores' n = [x | x <- [1..n], rem n x == 0]
divisoresPrimos' :: Int -> [Int]
divisoresPrimos' y = [ m | m <- [2..y], divisores' m == [1,m], rem y m == 0]  -- Prof: debería usar divisores'?
-- Nicolás Rodríguez Ruiz
divisoresPrimos x = [a | a <- (primos x), x `mod`a == 0]
                where primos n = [a | a <- [1..n], divisores a == [1,a]]
                      divisores n = [ a | a <- [1..n], n `mod` a == 0]
-- Ana Sosa Caballero
divisoresPrimos :: Int -> [Int]
divisoresPrimos x = [ n | n <- divisores x, primo n]

divisores x = [ n | n <- [1..x] , mod x n == 0]

primo x = divisores x == [1,x]
-- ---------------------------------------------------------------------
-- Ejercicio 2. Un número es libre de cuadrados si no es divisible por el
-- cuadrado de ningún entero mayor que 1. Por ejemplo, 70 es libre de
-- cuadrado porque sólo es divisible por 1, 2, 5, 7 y 70; en cambio, 40
-- no es libre de cuadrados porque es divisible por 2^2. 
-- 
-- Definir la función  
--    libreDeCuadrados :: Int -> Bool
-- tal que (libreDeCuadrados x) se verifica si x es libre de cuadrados. 
-- Por ejemplo,  
--    libreDeCuadrados 70  ==  True
--    libreDeCuadrados 40  ==  False
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos
libreDeCuadrados :: Int -> Bool
libreDeCuadrados n = null [x | x<- cuadrados n, mod n x == 0]
                   where cuadrados n = [x^2 | x <- [2..n]]
-- Nicolás Rodríguez Ruiz
libreDeCuadrados n =  [ a | a <- divisores n, (sq a) == (ndsq a) ] == [] -- Si el conjunto esta vacio => n no es producto de cuadrados
		           where divisores n = [ a | a <- [2..n-1], n `mod` a == 0]
		                 sq a = sqrt (fromIntegral a) -- Raiz con decimales
		                 ndsq a = fromIntegral(truncate (sq a)) -- Raiz sin decimales
-- Ana Sánchez Martín
libreDeCuadrados :: Int -> Bool
libreDeCuadrados n = n == product([x |x <- divisores n, primo x])

-- ---------------------------------------------------------------------
-- Ejercicio 3. [Del problema 21 del Proyecto Euler]. Sea d(n) la suma
-- de los divisores propios de n. Si d(a) = b y d(b) = a, siendo a
-- distinto de b,  
-- decimos que a y b son un par de números amigos. Por ejemplo, los
-- divisores propios de 220 son 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 y
-- 110; por tanto, d(220) = 284. Los divisores propios de 284 son 1, 2,
-- 4, 71 y 142; por tanto,  d(284) = 220.  Luego, 220 y 284 son dos
-- números amigos. 
-- 
-- Definir la función 
--    amigos :: Int -> Int -> Bool
-- tal que (amigos a b) se verifica si a y b son números amigos. Por
-- ejemplo, 
--    amigos 6 6       == False
--    amigos 220 248   == False
--    amigos 220 284   == True
--    amigos 100 200   == False
--    amigos 1184 1210 == True
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos
divisores :: Int -> [Int]
divisores n = [x | x<-[1..n], mod n x == 0]

amigos1 :: Int -> Int -> Bool
amigos1 a b = and [sumaDivisores a == b && sumaDivisores b == a, a/=b]
         where sumaDivisores n  = sum(divisores n) - n

-- Prof: En clase hemos visto
divisoresP :: Int -> [Int]
divisoresP n = [x | x<-[1..n-1], rem n x == 0]

amigos2 :: Int -> Int -> Bool
amigos2 a b = sumaDivisores a == b && sumaDivisores b == a && a/=b
         where sumaDivisores n  = sum(divisoresP n)

-- Prof: he movido aquí esta solución que estaba en el primer ejercicio
-- José Manuel García
d x = [n | n <- [1..x], rem x n == 0]
sumad x = sum (d x) 

amigos3 :: Int -> Int -> Bool
amigos3 a b = if a == b then False else sumad a == sumad b
-- Ana Sánchez Martín
amigos4 :: Int -> Int -> Bool
amigos4 a b = a /= b && sum (init(divisores a)) == b && sum (init(divisores b)) == a
-- Ana Sosa Caballero
amigos :: Int -> Int -> Bool
amigos a b = and [ d(a) == b, d(b) == a, a/= b]

divisores' x = [ n | n <- [1..x-1] , mod x n == 0]

d(n) = sum (divisores' n)

-- ---------------------------------------------------------------------
-- Ejercicio 4. (Problema 211 del proyecto Euler) Dado un entero
-- positivo n, consideremos la suma de los cuadrados de sus divisores,
-- Por ejemplo,  
--    f(10) = 1 + 4 + 25 + 100 = 130
--    f(42) = 1 + 4 +  9 +  36 + 49 + 196 + 441 + 1764 = 2500
-- Decimos que n es especial si f(n) es un cuadrado perfecto. En los
-- ejemplos anteriores, 42 es especial y 10 no lo es.
-- 
-- Definir la función 
--    especial:: Int -> Bool
-- tal que (especial x) se verifica si x es un número es especial. Por
-- ejemplo, 
--    especial 42  ==  True
--    especial 10  ==  False
--
-- Calcular todos los números especiales de tres cifras.
-- El resultado es:
-- λ> calculo
-- [246,287,728]
-- ---------------------------------------------------------------------
-- Lucía Hernández, Adolfo Sagrera Vivancos, Elsa Domínguez
sumaDivisoresCuadrados n = sum [ x^2  | x<- divisores n]
especial :: Int -> Bool
especial n = x^2 == sumaDivisoresCuadrados n
  where s = fromIntegral (sumaDivisoresCuadrados n)
        x = floor (sqrt s)

-- Prof: Otra solución sin usar floor ni sqrt (aunque más lenta)
especial2 :: Int -> Bool
especial2 n = elem s [  x^2 | x <-[1 .. s]]
  where s = sumaDivisoresCuadrados n

-- Lucía Hernández
especial3 = [ x | x<-[100..999], especial x]
--  Ana Sánchez Martín
esCuadrado x = or [x == n^2 | n <- [1..x]]
especial :: Int -> Bool
especial x = esCuadrado (sum (map (^2) (divisores x)))
especiales3 = [x | x <- [100..999], especial x]

-- ---------------------------------------------------------------------
-- Ejercicio 5. La multiplicidad de x en y es la mayor potencia de x
-- que divide a y. Por ejemplo, la multiplicidad de 2 en 40 es 3 porque
-- 40 es divisible por 2^3 y no lo es por 2^4. Además, la multiplicidad
-- de 1 en cualquier número se supone igual a 1. 
-- 
-- Definir la función
--    multiplicidad :: Integer -> Integer -> Integer
-- tal que (multiplicidad x y) es la
-- multiplicidad de x en y. Por ejemplo,
--    multiplicidad 2 40  ==  3
--    multiplicidad 5 40  ==  1
--    multiplicidad 3 40  ==  0
--    multiplicidad 1 40  ==  1
-- ---------------------------------------------------------------------
-- Lucía Hernández
multiplicidad :: Integer -> Integer -> Integer
multiplicidad 1 _ = 1
multiplicidad x y = last  [ s | s<-[0..y], elem (x^s) (potencias x), elem (x^s)(divisores y)]
       where potencias n = [n^s | s<-[0..y]]
-- Prof: en esta solución se puede simplificar lo siguiente:
-- -  elem (x^s) (potencias x) no hace falta, ya que siempre se va a cumplir
-- -  elem (x^s)(divisores y) se puede simplificar a simplemente comprobar si x^s divide a y

-- Elsa Domínguez, Ana Sánchez Martín
multiplicidad1 :: Integer -> Integer -> Integer
multiplicidad1 x y = if x == 1 then 1 else sum [1 | n <- [1..y], rem y (x^n) == 0]

-- Nicolás Rodríguez Ruiz
multiplicidad a b = sum [1 | x <- [1..length(divisores b)], a^x `elem` (divisores b)]
  where divisores n = [ a | a <- [1..n], n `mod` a == 0]
-- Prof: en esta solución se puede simplificar lo siguiente:
-- -   a^x `elem` (divisores b) se puede simplificar a simplemente comprobar si a^x divide a b
-- Adolfo Sagrera Vivancos
multiplicidad2 :: Integer -> Integer -> Integer
multiplicidad2 1 _ = 1
multiplicidad2 x y = last [s | s <- [0..y], rem y (x^s) == 0]

-- -------------------------------------------------------------
-- Ejercicio 6.1. Sea t una lista de pares de la forma 
--    (nombre, [(asig_1, nota_1),...,(asig_k, nota.k)])
-- Por ejemplo, 
--    t1 = [("Ana",[("Alg",1),("Cal",3),("Inf",8),("Fis",2)]),
--          ("Juan",[("Alg",5),("Cal",1),("Inf",2),("Fis",9)]),
--          ("Alba",[("Alg",5),("Cal",6),("Inf",6),("Fis",5)]),
--          ("Pedro",[("Alg",9),("Cal",5),("Inf",3),("Fis",1)])]
-- Definir la función 
--    calificaciones :: [(String,[(String,Int)])] -> String -> [(String,Int)]
-- tal que (calificaciones t p) es la lista de las calificaciones de la
-- persona p en la lista t. Por ejemplo, 
--    ghci> calificaciones t1 "Pedro"
--    [("Alg",9),("Cal",5),("Inf",3),("Fis",1)]
-- ---------------------------------------------------------------------

t1 :: [(String,[(String,Int)])]
t1 = [("Ana",[("Alg",1),("Cal",3),("Inf",8),("Fis",2)]),
      ("Juan",[("Alg",5),("Cal",1),("Inf",2),("Fis",9)]),
      ("Alba",[("Alg",5),("Cal",6),("Inf",6),("Fis",5)]),
      ("Pedro",[("Alg",9),("Cal",5),("Inf",3),("Fis",1)])]

--Nicolás Rodríguez Ruiz, Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos, Ana Sánchez Martín, Ana Sosa Caballero
calificaciones :: [(String,[(String,Int)])] -> String -> [(String,Int)]
calificaciones t p = head[  ns | (nom, ns) <- t, nom == p ]

-- ---------------------------------------------------------------------
-- Ejercicio 6.2. Definir la función  
--    todasAprobadas :: [(String,[(String,Int)])] -> String -> Bool
-- tal que (todasAprobadas t p) se cumple si en la lista t, p tiene
-- todas las asignaturas aprobadas. Por ejemplo,
--    todasAprobadas t1 "Alba"  ==  True
--    todasAprobadas t1 "Pedro" ==  False
-- ---------------------------------------------------------------------

-- Nicolás Rodríguez Ruiz, Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos, Ana Sánchez Martín, Ana Sosa Caballero
todasAprobadas :: [(String,[(String,Int)])] -> String -> Bool
todasAprobadas t p = and[n>=5 | (_, n) <- (calificaciones t p)]

-- ---------------------------------------------------------------------
-- Ejercicio 6.3. Definir la función  
--    aprobados :: [(String,[(String,Int)])] -> [String]
-- tal que (aprobados t) es la lista de los alumnos de la lista de notas
-- t que han aprobado todas las asignaturas.Por ejemplo,
--    ghci> aprobados t1  ==  ["Alba"]
-- ---------------------------------------------------------------------

-- Nicolás Rodríguez Ruiz, Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos, Ana Sánchez Martín
aprobados :: [(String,[(String,Int)])] -> [String]
aprobados t = [nom | (nom, _) <- t, todasAprobadas t nom]

-- ---------------------------------------------------------------------
-- Ejercicio 7. Un número n es de Angelini si n y 2n tienen algún
-- dígito común. Por ejemplo, 2014 es un número de Angelini ya que 2014
-- y su doble (4028) comparten los dígitos 4 y 0.
--
-- Definir la función
--    angelini :: Integer -> Bool
-- tal que (angelini n) se verifica si n es un número de Angelini. Por
-- ejemplo, 
--    angelini 2014  ==  True
--    angelini 2067  ==  False
-- ---------------------------------------------------------------------

-- Elsa Domínguez, Adolfo Sagrera Vivancos
angelini :: Integer -> Bool
angelini n = not (null (cifrasIguales n))
           where cifrasIguales n = [a | (a,b) <- ns, a == b]   -- Prof: se puede simplificar con la función elem
                 ns = [(a,b) | a <- cifras n, b <- cifras (2*n)]

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

-- Nicolás Rodríguez Ruiz, Ana Sánchez Martín
angelini1 :: Integer -> Bool
angelini1 n = or[c `elem` (show (2*n)) | c <- (show n)]

-- Ana Sosa Caballero
angelini :: Integer -> Bool
angelini n =  or [ x == y | x <- digitos n, y <- digitos (2*n)]

digitos 0 = []
digitos n = digitos (div n 10 ) ++ [rem n 10]


-- ---------------------------------------------------------------------
-- Ejercicio 8.1. Definir la función 
--    unitarios :: Int -> [Int]
-- tal (unitarios n) es la lista de números [n,nn, nnn, ....]. Por
-- ejemplo.  
--    take 7 (unitarios 3) == [3,33,333,3333,33333,333333,3333333]
--    take 3 (unitarios 1) == [1,11,111]
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Adolfo Sagrera Vivancos, Ana Sánchez Martín
repetir x n  = sum [x*10^i | i<-[0..n-1]] 
unitarios :: Int -> [Int]
unitarios x = [ (repetir x n) | n<- [1..]]

--Nicolás Rodríguez Ruiz
unitarios x = [ sum[  x*(10^a) | a <- [0..n] ] | n <- [1..]]

-- ---------------------------------------------------------------------
-- Ejercicio 8.2. Definir la función 
--    multiplosUnitarios :: Int -> Int -> Int -> [Int]
-- tal que (multiplosUnitarios x y n) es la lista de los n primeros
-- múltiplos de x cuyo único dígito es y. Por ejemplo,
--    multiplosUnitarios 7 1 2  == [111111,111111111111]
--    multiplosUnitarios 11 3 5 == [33,3333,333333,33333333,3333333333]
-- ---------------------------------------------------------------------

-- Lucía Hernández, Elsa Domínguez, Ana Sánchez Martín, Adolfo Sagrera Vivancos
multiplosUnitarios :: Int -> Int -> Int -> [Int]
multiplosUnitarios x y n = take n ([a  | a<- unitarios y, mod a x == 0])

-- ---------------------------------------------------------------------
-- Ejercicio 9. Definir la función 
--    masOcurrentes :: Eq a => [a] -> [a]
-- tal que (masOcurrentes xs) es la lista de los elementos de xs que
-- ocurren el máximo número de veces. Por ejemplo,
--    masOcurrentes [1,2,3,4,3,2,3,1,4] == [3,3,3]
--    masOcurrentes [1,2,3,4,5,2,3,1,4] == [1,2,3,4,2,3,1,4]
--    masOcurrentes "Salamanca"         == "aaaa"
-- ---------------------------------------------------------------------

--Nicolás Rodríguez Ruiz y Elsa Domínguez
masOcurrentes :: Eq a => [a] -> [a]
masOcurrentes xs = [ b | (a,b) <- (paresOrd xs), a ==( maximum (numVeces xs))]
  where paresOrd xs = zip (numVeces xs) xs
        numVeces xs = [veces x xs | x <- xs]
        veces n xs = sum[ 1 | x <- xs, x ==n]

-- Fernando Ruiz, Ana Sánchez Martín
masOcurrentes' xs = [ a | a <- xs , ocurrencia a xs == maximum (ocurrencias xs) ]

ocurrencias xs = [ ocurrencia a xs | a <- xs]
ocurrencia a xs = sum [ 1 | b <- xs, b == a]

--Manuel ALcaide 
agrup xs = group (sort xs)

vecesqueaparecen xs = nub [(n,length v)|n<-xs,v<- agrup xs, elem n v]

listapoyo xs = [(g,h)|g<-(xs),(l,h)<-(vecesqueaparecen xs),g==l]

masOcurrentes'' :: Ord a => [a] -> [a]
masOcurrentes'' xs
   |length (nub [m|(_,m)<-(vecesqueaparecen xs)]) == 1 = xs
   |otherwise = [p|(p,q)<-(listapoyo xs) , q == maximum ([m|(_,m)<-(vecesqueaparecen xs)])]
-- Adolfo Sagrera Vivancos
masOcurrentes :: Ord a => [a] -> [a]
masOcurrentes xs = [x | x <- xs, longitud xs == veces x xs]
ordenados xs = group (sort xs)
longitud xs = maximum [length n | n <- ordenados xs]
veces n xs = sum[1 | a <- xs, n == a]

-- ---------------------------------------------------------------------
-- Ejercicio 10. La suma de la serie
--    1/1^2 + 1/2^2 + 1/3^2 + 1/4^2 + ...
-- es pi^2/6. Por tanto, pi se puede aproximar mediante la raíz cuadrada
-- de 6 por la suma de la serie.
-- 
-- Definir la función aproximaPi tal que (aproximaPi n) es la aproximación 
-- de pi obtenida mediante n términos de la serie. Por ejemplo, 
--    aproximaPi 4    == 2.9226129861250305
--    aproximaPi 1000 == 3.1406380562059946
-- ---------------------------------------------------------------------

-- Elsa Domínguez, Adolfo Sagrera Vivancos, Ana Sánchez Martín, Ana Sosa Caballero
aproximaPi n = sqrt (6*sum [1/x^2 | x <- [1..n]])

-- ---------------------------------------------------------------------
-- Ejercicio 11. Una representación de 20 en base 2 es [0,0,1,0,1] pues
-- 20 = 1*2^2 + 1*2^4. Y una representación de 46 en base 3 es [1,0,2,1]
-- pues 46 = 1*3^0 + 0*3^1 + 2*3^2 + 1*3^3.
-- 
-- Definir la función 
--    deBaseABase10 :: Int -> [Int] -> Int
-- tal que (deBaseABase10 b xs) es el número n tal que su representación
-- en base b es xs. Por ejemplo, 
--    deBaseABase10 2 [0,0,1,0,1]      == 20
--    deBaseABase10 2 [1,1,0,1]        == 11
--    deBaseABase10 3 [1,0,2,1]        == 46
--    deBaseABase10 5 [0,2,1,3,1,4,1]  == 2916
-- ---------------------------------------------------------------------
-- Lucía Hernández, Elsa Domínguez, Ana Sánchez Martín
deBaseABase10 :: Int -> [Int] -> Int
deBaseABase10 b xs = sum [i*( b^n)  | (i,n)<- zip  xs [0..length xs -1] ]
-- Adolfo Sagrera Vivancos
deBaseABase10' :: Int -> [Int] -> Int
deBaseABase10' b xs = sum[ n*(b^c) | (n,c) <- posicion xs]
posicion xs = zip xs [0..]

-- ---------------------------------------------------------------------
-- Ejercicio 12.1. Definir la función 
--    conPos :: [a] -> [(a,Int)]
-- tal que (conPos xs) es la lista obtenida a partir de xs especificando
-- las posiciones de sus elementos. Por ejemplo, 
--    conPos [1,5,0,7] == [(1,0),(5,1),(0,2),(7,3)]
-- ---------------------------------------------------------------------
-- Lucía Hernández
conPos :: [a] -> [(a,Int)]
conPos xs = [ (x,y) | (x,y)<- zip xs ys]
       where ys = [0..length xs - 1]
-- Elsa Domínguez, Ana Sánchez Martín
conPos1 :: [a] -> [(a,Int)]
conPos1 xs = zip xs [0..length xs-1]
-- Adolfo Sagrera Vivancos
conPos' :: [a] -> [(a,Int)]
conPos' xs = zip xs [0..]

-- ---------------------------------------------------------------------
-- Ejercicio 12.2. Definir la función
--    pares :: [a] -> [a]
-- tal que (pares cs) es la cadena formada por los caracteres en
-- posición par de cs. Por ejemplo,  
--    pares "el cielo sobre berlin" == "e il or eln"
-- ---------------------------------------------------------------------

-- Elsa Domínguez, Ana Sánchez Martín, Adolfo Sagrera Vivancos
pares :: [a] -> [a]
pares cs = [a | (a,b) <- conPos cs, even b]

-- ---------------------------------------------------------------------
-- Ejercicio 13. Dos listas xs, ys de la misma longitud son
-- perpendiculares si el producto escalar de ambas es 0, donde el
-- producto escalar de dos listas de enteros xs e ys viene
-- dado por la suma de los productos de los elementos correspondientes.
-- 
-- Definir la función 
--    perpendiculares :: (Num a, Eq a) => [a] -> [[a]] -> [[a]]
-- tal que (perpendiculares xs yss) es la lista de los elementos de yss
-- que son perpendiculares a xs. Por ejemplo,
--    ghci> perpendiculares [1,0,1] [[0,1,0], [2,3,1], [-1,7,1],[3,1,0]]
--    [[0,1,0],[-1,7,1]]
-- ---------------------------------------------------------------------

--Nicolás Rodríguez Ruiz y Elsa Domínguez, Adolfo Sagrera Vivancos
perpendiculares :: (Num a, Eq a) => [a] -> [[a]] -> [[a]]
perpendiculares xs yss = [ ys | ys <- yss, xs `productoEscalar` ys==0]
  where productoEscalar xs ys = sum [a*x | (a,x) <- zip xs ys]

-- Ana Sánchez Martín
productoEscalar xs ys = sum [a*x | (a,x) <- zip xs ys]
-- Una vez tengamos la función productoEscalar hacemos perpendiculares
perpendiculares :: (Num a, Eq a) => [a] -> [[a]] -> [[a]]
perpendiculares xs yss = [ys | ys <- yss, productoEscalar xs ys == 0]

-- ---------------------------------------------------------------------
-- Ejercicio 14. Dada una lista de números enteros, definiremos el
-- mayor salto como el mayor valor de las diferencias (en valor
-- absoluto) entre números consecutivos de la lista. Por ejemplo, dada
-- la lista [2,5,-3] las distancias son 
--    3 (valor absoluto de la resta 2 - 5) y
--    8 (valor absoluto de la resta de 5 y (-3))
-- Por tanto, su mayor salto es 8. No está definido el mayor salto para
-- listas con menos de 2 elementos
--
-- Definir la función 
--    mayorSalto :: [Integer] -> Integer
-- tal que (mayorSalto xs) es el mayor salto de la lista xs. Por
-- ejemplo, 
--    mayorSalto [1,5]              == 4
--    mayorSalto [10,-10,1,4,20,-2] == 22
-- ---------------------------------------------------------------------

-- Elsa Domínguez, Ana Sánchez Martín, Adolfo Sagrera Vivancos
mayorSalto :: [Integer] -> Integer
mayorSalto xs = maximum [abs (a-b) | (a,b) <- zip xs (tail xs)]

-- ---------------------------------------------------------------------
-- Ejercicio 15. Definir la función
--    longCamino :: [(Float,Float)] -> Float
-- tal que (longCamino xs) es la longitud del camino determinado por los
-- puntos del plano listados en xs. Por ejemplo,
--    longCamino [(0,0),(1,0),(2,1),(2,0)] == 3.4142137
-- ---------------------------------------------------------------------

--Elsa Domínguez y Nicolás Rodríguez Ruiz, Ana Sánchez Martín
longCamino :: [(Float,Float)] -> Float
longCamino xs = sum [distancia a b | (a,b) <- zip xs (tail xs)]
  where distancia (a,b) (x,y) = sqrt((x-a)^2 + (y-b)^2)
-- Adolfo Sagrera Vivancos
longCamino1 :: [(Float,Float)] -> Float
longCamino1 xs = sum [ sqrt ((c-a)^2 + ((d-b)^2)) | ((a,b),(c,d)) <- agrupa xs]
agrupa xs = zip (init xs) (tail xs)

-- ---------------------------------------------------------------------
-- Ejercicio 16. Definir la función
--    numeroConsecutivos :: (Num a, Eq a) => [a] -> Int
-- tal que (numeroConsecutivosC xs) es la cantidad de números
-- consecutivos que aparecen al comienzo de la lista xs. Por ejemplo, 
--    numeroConsecutivosC [1,3,5,7,9]      ==  1
--    numeroConsecutivosC [1,2,3,4,5,7,9]  ==  5
--    numeroConsecutivosC []               ==  0
-- ---------------------------------------------------------------------

-- Prof; posibles soluciones
-- 1ª solución (con índices)
numeroConsecutivosC :: (Num a, Eq a) => [a] -> Int
numeroConsecutivosC xs
    | null ys   = length xs
    | otherwise = head ys
    where ys = [n | n <- [1..length xs -1], xs !! n /= 1 + xs !! (n-1)]

-- 2ª solución (con zip3)
numeroConsecutivosC2 :: (Num a, Eq a) => [a] -> Int
numeroConsecutivosC2 [] = 0
numeroConsecutivosC2 [x] = 1
numeroConsecutivosC2 [x,y] | x+1 == y  = 2
                           | otherwise = 1
numeroConsecutivosC2 xs =
    head [k | (x,y,k) <- zip3 xs (tail xs) [1..], y /= x+1]
--Adolfo Sagrera Vivancos
numeroConsecutivos xs = sum [ 1  | (a,b) <- posicion1 xs, a == b]
posicion1 xs = zip xs [1..]

-- ---------------------------------------------------------------------
-- Ejercicio 17. Definir la función
--    sumaEquidistantes :: Num a => [a] -> [a]
-- tal que (sumaEquidistantes xs) es la lista sumando el primer elemento
-- de xs con el último, el segundo con el penúltimo y así
-- sucesivamente. Por ejemplo, 
--    sumaEquidistantes [6,5,3,1]              ==  [7,8]
--    sumaEquidistantes [6,5,3]                ==  [9,10]
--    sumaEquidistantes [3,2,3,2]              ==  [5,5]
--    sumaEquidistantes [6,5,3,1,2,0,4,7,8,9]  ==  [15,13,10,5,2]
-- ---------------------------------------------------------------------

-- Elsa Domínguez, Ana Sánchez Martín
sumaEquidistantes :: Num a => [a] -> [a]
sumaEquidistantes xs = reverse (drop (div (length xs) 2) [a+b | (a,b) <- zip xs (reverse xs)])
-- Adolfo Sagrera Vivancos
sumaEquidistantes xs = nub [ a+b   | (a,b) <- agrupa1 xs]
agrupa1 xs = (zip xs (reverse xs))

-- ---------------------------------------------------------------------
-- Ejercicio 18. La distancia entre dos números es el valor absoluto de
-- su diferencia. Por ejemplo, la distancia entre 2 y 5 es 3. 
-- 
-- Definir la función
--    cercanos :: [Int] -> [Int] -> [(Int,Int)]
-- tal que (cercanos xs ys) es la lista de pares de elementos de xs e ys
-- cuya distancia es mínima. Por ejemplo,
--    cercanos [3,7,2,1] [5,11,9]  ==  [(3,5),(7,5),(7,9)]
-- ---------------------------------------------------------------------
-- Lucía Hernández, Ana Sánchez Martín, Adolfo Sagrera Vivancos
distancia x y = abs(x-y)
cercanos :: [Int] -> [Int] -> [(Int,Int)]
cercanos xs ys = [(x,y) | x<- xs, y<-ys, distancia x y == minimum [distancia x' y' | x'<- xs, y'<-ys]]

-- Elsa Domínguez 
cercanos1 :: [Int] -> [Int] -> [(Int,Int)]
cercanos1 xs ys = [(a,b) | a <- xs, b <- ys, abs (a-b) == minimum (distanciaPares xs ys)]

distanciaPares xs ys = [abs (a-b) | a <- xs, b <- ys]

-- ---------------------------------------------------------------------
-- Ejercicio 19. [De la IMO 1996]. Una sucesión [a(0),a(1),...,a(n)] 
-- se denomina cuadrática si para cada i   {1, 2,..., n} se cumple que 
--    |a(i)- a(i-1)| = i^2 .
-- 
-- Definir la función
--    esCuadratica :: [Int] -> Bool
-- tal que (esCuadratica xs) se verifica si xs cuadrática.  Por ejemplo,
--    esCuadratica [2,1,-3,6]                      == True
--    esCuadratica [2,1,3,5]                       == False
--    esCuadratica [3,4,8,17,33,58,94,45,-19,-100] == True
-- ---------------------------------------------------------------------

-- Elsa Domínguez
esCuadratica :: [Int] -> Bool
esCuadratica xs = [abs (a-b) | (a,b) <- ys] == [x^2 | x <- [1..length (ys)]]
                where ys  = zip (tail xs) xs

-- Prof: otra opción
esCuadratica :: [Int] -> Bool
esCuadratica xs = and [abs (a-b) == x^2 | (a,b,x) <- zip3 (tail xs) xs [1..]]

-- ---------------------------------------------------------------------
-- Ejercicio 20.1. Definir las funciones  
--    ultima, primera :: Int -> Int  
-- tales que
-- * (ultima n) es la última cifra del número natural n y
-- * (primera n) es la primera cifra del número natural n.
-- Por ejemplo,
--    ultima  711 = 1         
--    primera 711 = 7
-- ---------------------------------------------------------------------

--Nicolás Rodríguez Ruiz y Elsa Domínguez, Ana Sánchez Martín
ultima, primera :: Int -> Int  
ultima n  = rem n 10
primera n =  read [head (show n)]  
-- prof: también con digitToInt de Data.Char
-- Adolfo Sagrera Vivancos
ultima1 n  = last(cifras n)
primera1 n = head (cifras n)


-- ---------------------------------------------------------------------
-- Ejercicio 20.2. Definir la función
--    encadenadoC :: [Int] -> Bool
-- tal que (encadenadoC xs) se verifica si xs es una lista de enteros
-- positivos encadenados (es decir, la última cifra de cada número
-- coincide con la primera del siguiente en la lista). Por ejemplo,
--   encadenadoC [711,1024,413,367]  ==  True
--   encadenadoC [711,1024,213,367]  ==  False
-- ---------------------------------------------------------------------

-- Elsa Domínguez y Nicolás Rodríguez Ruiz, Ana Sánchez Martín, Adolfo Sagrera Vivancos
encadenadoC :: [Int] -> Bool
encadenadoC xs = and [ ultima a == primera b | (a,b) <- zip xs (tail xs)]