En este ejercicio, se representa un mapa mediante una lista de listas de la misma longitud donde todos sus elementos son 0 menos uno (que es un 1) que es donde se encuentra la mina. Por ejemplo, en el mapa
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 1 0 0
la posición de la mina es (2,1).
Definir la función
posicionMina :: [[Int]] -> (Int,Int)
posicionMina :: [[Int]] -> (Int,Int)
tal que (posicionMina m) es la posición de la mina en el mapa m, Por ejemplo,
¡El mundo está en cuarentena! Hay una nueva pandemia que lucha contra la humanidad. Cada continente está aislado de los demás, pero las personas infectadas se han propagado antes de la advertencia.
En este problema se representará el mundo por una cadena como la siguiente
"01000000X000X011X0X"
"01000000X000X011X0X"
donde 0 representa no infectado, 1 representa infectado y X representa un océano
Las reglas de propagación son:
El virus no puede propagarse al otro lado de un océano.
Si una persona se infecta, todas las personas de este continente se infectan también.
El primer y el último continente no están conectados.
El problema consiste en encontrar el porcentaje de la población humana que se infectó al final. Por ejemplo,
import Data.List (genericLength)import Data.List.Split (splitOn)-- 1ª solución-- ===========
porcentajeInfectados ::String->Double
porcentajeInfectados xs
| nh ==0=0|otherwise=100* ni / nh
where ni =fromIntegral(numeroInfectados xs)
nh =fromIntegral(numeroHabitantes xs)-- (continentes xs) es la lista de las poblaciones de los continentes-- del mapa xs. Por ejemplo,-- continentes "01000000X000X011X0X" == ["01000000","000","011","0"]-- continentes "01X000X010X011XX" == ["01","000","010","011"]-- continentes "XXXXX" == [""]-- continentes "0000000010" == ["0000000010"]-- continentes "X00X000000X10X0100" == ["","00","000000","10","0100"]
continentes ::String->[String]
continentes []=[]
continentes xs =as: continentes (dropWhile(=='X') bs)where(as,bs)=break(=='X') xs
-- (numeroInfectados xs) es el número final de infectados a partir del-- mapa xs. Por ejemplo,-- numeroInfectados "01000000X000X011X0X" == 11
numeroInfectados ::String->Int
numeroInfectados xs =sum[length ys | ys <- continentes xs
, '1' `elem` ys]-- (numeroHabitantes xs) es el número final de habitantes del mapa-- xs. Por ejemplo, -- numeroHabitantes "01000000X000X011X0X" == 15
numeroHabitantes ::String->Int
numeroHabitantes xs =length(filter(/='X') xs)-- 2ª solución-- ===========
porcentajeInfectados2 ::String->Double
porcentajeInfectados2 xs
| nh ==0=0|otherwise=100* ni / nh
where ni =sum[genericLength ys | ys <- splitOn "X" xs, '1' `elem` ys]
nh = genericLength (filter(/='X') xs)
import Data.List (genericLength)
import Data.List.Split (splitOn)
-- 1ª solución
-- ===========
porcentajeInfectados :: String -> Double
porcentajeInfectados xs
| nh == 0 = 0
| otherwise = 100 * ni / nh
where ni = fromIntegral (numeroInfectados xs)
nh = fromIntegral (numeroHabitantes xs)
-- (continentes xs) es la lista de las poblaciones de los continentes
-- del mapa xs. Por ejemplo,
-- continentes "01000000X000X011X0X" == ["01000000","000","011","0"]
-- continentes "01X000X010X011XX" == ["01","000","010","011"]
-- continentes "XXXXX" == [""]
-- continentes "0000000010" == ["0000000010"]
-- continentes "X00X000000X10X0100" == ["","00","000000","10","0100"]
continentes :: String -> [String]
continentes [] = []
continentes xs = as : continentes (dropWhile (=='X') bs)
where (as,bs) = break (=='X') xs
-- (numeroInfectados xs) es el número final de infectados a partir del
-- mapa xs. Por ejemplo,
-- numeroInfectados "01000000X000X011X0X" == 11
numeroInfectados :: String -> Int
numeroInfectados xs =
sum [length ys | ys <- continentes xs
, '1' `elem` ys]
-- (numeroHabitantes xs) es el número final de habitantes del mapa
-- xs. Por ejemplo,
-- numeroHabitantes "01000000X000X011X0X" == 15
numeroHabitantes :: String -> Int
numeroHabitantes xs = length (filter (/='X') xs)
-- 2ª solución
-- ===========
porcentajeInfectados2 :: String -> Double
porcentajeInfectados2 xs
| nh == 0 = 0
| otherwise = 100 * ni / nh
where ni = sum [genericLength ys | ys <- splitOn "X" xs, '1' `elem` ys]
nh = genericLength (filter (/='X') xs)
Otras soluciones
Se pueden escribir otras soluciones en los comentarios.
El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>
Pensamiento
“El avance de las matemáticas puede ser visto como un progreso de lo infinito a lo finito.”
La propiedad de la longitud de la parte periódica afirma que
Si p es un número primo distinto de 2 y de 5, entonces la longitud del período de 1/p es el menor entero positivo n tal que p divide a .
El objetivo de este ejercicio es la verificación de dicha propiedad.
Las fracciones se representan por un par de enteros. Por ejemplo, el número 2/3 se representa por (2,3). Su tipo es
type Fraccion = (Integer,Integer)
type Fraccion = (Integer,Integer)
Los números decimales se representan por ternas, donde el primer elemento es la parte entera, el segundo es el anteperíodo y el tercero es el período. Por ejemplo,
6/2 = 3 se representa por (3,[],[])
1/2 = 0.5 se representa por (0,[5],[])
1/3 = 0.333333... se representa por (0,[],[3])
23/14 = 1.6428571428571... se representa por (1,[6],[4,2,8,5,7,1])
6/2 = 3 se representa por (3,[],[])
1/2 = 0.5 se representa por (0,[5],[])
1/3 = 0.333333... se representa por (0,[],[3])
23/14 = 1.6428571428571... se representa por (1,[6],[4,2,8,5,7,1])
Su tipo es
type Decimal = (Integer,[Integer],[Integer])
type Decimal = (Integer,[Integer],[Integer])
Definir, usando las funciones cocientesRestos y primerRepetido de los ejercicios anteriores, las funciones
Comprobar con QuickCheck la propiedad de la longitud de la parte periódica; es decir, k es un número natural distinto de 0 y 2 y p es el primo k-ésimo, entonces la longitud del período de 1/p es el menor entero positivo n tal que p divide a ..
Soluciones
import Data.Numbers.Primes
import Test.QuickCheck
type Fraccion =(Integer,Integer)type Decimal =(Integer,[Integer],[Integer])
decimal :: Fraccion -> Decimal
decimal (n,d)|snd y ==0=(fst x, mapfst xs, [])|otherwise=(fst x, mapfst xs, mapfst(y:zs))where
qrs = cocientesRestos (n,d)
Just (q,r)= primerRepetido qrs
(x:xs,y:ys)=break(==(q,r)) qrs
zs =takeWhile(/=(q,r)) ys
cocientesRestos :: Fraccion ->[(Integer,Integer)]
cocientesRestos (n,d)=(q,r): cocientesRestos (10*r, d)where(q,r)=quotRem n d
primerRepetido ::Eq a =>[a]->Maybe a
primerRepetido xs = aux xs []where
aux [] _ = Nothing
aux (x:xs') ys | x `elem` ys = Just x
|otherwise= aux xs' (x:ys)
longitudPeriodo :: Fraccion ->Int
longitudPeriodo (n,d)=length xs
where(_,_,xs)= decimal (n,d)-- La propiedad es
prop_LongitudPeriodo ::Int-> Property
prop_LongitudPeriodo k =
k >0&& k /=2==>
longitudPeriodo (1,p)==head[n | n <-[1..], (10^n-1) `mod` p ==0]where p = primes !! k
-- La comprobación es-- λ> quickCheck prop_LongitudPeriodo-- +++ OK, passed 100 tests.
import Data.Numbers.Primes
import Test.QuickCheck
type Fraccion = (Integer,Integer)
type Decimal = (Integer,[Integer],[Integer])
decimal :: Fraccion -> Decimal
decimal (n,d)
| snd y == 0 = (fst x, map fst xs, [])
| otherwise = (fst x, map fst xs, map fst (y:zs))
where
qrs = cocientesRestos (n,d)
Just (q,r) = primerRepetido qrs
(x:xs,y:ys) = break (==(q,r)) qrs
zs = takeWhile (/=(q,r)) ys
cocientesRestos :: Fraccion -> [(Integer,Integer)]
cocientesRestos (n,d) =
(q,r) : cocientesRestos (10*r, d)
where (q,r) = quotRem n d
primerRepetido :: Eq a => [a] -> Maybe a
primerRepetido xs = aux xs []
where
aux [] _ = Nothing
aux (x:xs') ys | x `elem` ys = Just x
| otherwise = aux xs' (x:ys)
longitudPeriodo :: Fraccion -> Int
longitudPeriodo (n,d) = length xs
where (_,_,xs) = decimal (n,d)
-- La propiedad es
prop_LongitudPeriodo :: Int -> Property
prop_LongitudPeriodo k =
k > 0 && k /= 2
==>
longitudPeriodo (1,p) ==
head [n | n <- [1..], (10^n-1) `mod` p == 0]
where p = primes !! k
-- La comprobación es
-- λ> quickCheck prop_LongitudPeriodo
-- +++ OK, passed 100 tests.
Otras soluciones
Se pueden escribir otras soluciones en los comentarios.
El código se debe escribir entre una línea con <pre lang=”haskell”> y otra con </pre>
Pensamiento
“En el desarrollo de la comprensión de los fenómenos complejos, la herramienta más poderosa de que dispone el intelecto humano es la abstracción. La abstracción surge del reconocimiento de las similitudes entre ciertos objetos, situaciones o procesos en el mundo real y de la decisión de concentrarse en estas similitudes e ignorar, por el momento, sus diferencias.”
tal que (divideSegun p xs) es la lista de los segmentos de xs cuyos elementos no cumplen la propiedad p. Por ejemplo,
divideSegun even [3,5,2,7,6,8,9,1] == [[3,5],[7],[9,1]]
divideSegun odd [3,5,2,7,6,8,9,1] == [[2],[6,8]]
divideSegun even [3,5,2,7,6,8,9,1] == [[3,5],[7],[9,1]]
divideSegun odd [3,5,2,7,6,8,9,1] == [[2],[6,8]]
Comprobar con QuickCheck que, para cualquier lista xs de números enteros, la concatenación de los elementos de (divideSegun even xs) es la lista de los elementos de xs que no son pares.
Soluciones
import Test.QuickCheck
divideSegun ::(a ->Bool)->[a]->[[a]]
divideSegun p xs
|null ys =[]|otherwise= ys : divideSegun p zs
where(ys,zs)=break p (dropWhile p xs)-- La propiedad es
prop_divideSegun ::[Int]->Bool
prop_divideSegun xs =concat(divideSegun even xs)==filter(not . even) xs
-- La comprobación es -- ghci> quickCheck prop_divideSegun-- +++ OK, passed 100 tests.
import Test.QuickCheck
divideSegun :: (a -> Bool) -> [a] -> [[a]]
divideSegun p xs
| null ys = []
| otherwise = ys : divideSegun p zs
where (ys,zs) = break p (dropWhile p xs)
-- La propiedad es
prop_divideSegun :: [Int] -> Bool
prop_divideSegun xs =
concat (divideSegun even xs) == filter (not . even) xs
-- La comprobación es
-- ghci> quickCheck prop_divideSegun
-- +++ OK, passed 100 tests.