Ir al contenido principal

Reparto de escaños por la ley d'Hont

El sistema D'Hondt es una fórmula electoral, creada por Victor d'Hondt, que permite obtener el número de cargos electos asignados a las candidaturas, en proporción a los votos conseguidos.

Tras el recuento de los votos, se calcula una serie de divisores para cada partido. La fórmula de los divisores es V/N, donde V representa el número total de votos recibidos por el partido, y N representa cada uno de los números enteros desde 1 hasta el número de cargos electos de la circunscripción objeto de escrutinio. Una vez realizadas las divisiones de los votos de cada partido por cada uno de los divisores desde 1 hasta N, la asignación de cargos electos se hace ordenando los cocientes de las divisiones de mayor a menor y asignando a cada uno un escaño hasta que éstos se agoten

Definir la función

reparto :: Int -> [Int] -> [(Int,Int)]

tal que (reparto n vs) es la lista de los pares formados por los números de los partidos y el número de escaño que les corresponden al repartir n escaños en función de la lista de sus votos. Por ejemplo,

λ> reparto 7 [340000,280000,160000,60000,15000]
[(1,3),(2,3),(3,1)]
λ> reparto 21 [391000,311000,184000,73000,27000,12000,2000]
[(1,9),(2,7),(3,4),(4,1)]

es decir, en el primer ejemplo,

  • al 1º partido (que obtuvo 340000 votos) le corresponden 3 escaños,
  • al 2º partido (que obtuvo 280000 votos) le corresponden 3 escaños,
  • al 3º partido (que obtuvo 160000 votos) le corresponden 1 escaño.

Soluciones

import Data.List (sort, group)

-- Para los ejemplos que siguen, se usará la siguiente ditribución de
-- votos entre 5 partidos.
ejVotos :: [Int]
ejVotos = [340000,280000,160000,60000,15000]

ejVotos2 :: [Int]
ejVotos2 = [391000,311000,184000,73000,27000,12000,2000]

-- λ> reparto 21 ejVotos2
-- [(1,9),(2,7),(3,4),(4,1)]

ejVotos3 :: [Int]
ejVotos3 = [221,195,40,6,4]

-- (votosPartidos vs) es la lista con los pares formados por los votos y
-- el número de cada partido. Por ejemplo,
--    λ> votosPartidos ejVotos
--    [(340000,1),(280000,2),(160000,3),(60000,4),(15000,5)]
votosPartidos :: [Int] -> [(Int,Int)]
votosPartidos vs = zip vs [1..]

-- (restos n (x,i)) es la lista obtenidas dividiendo n entre 1, 2,..., n.
-- Por ejemplo,
--    λ> restos 5 (340000,1)
--    [(340000,1),(170000,1),(113333,1),(85000,1),(68000,1)]
restos :: Int -> (Int,Int) -> [(Int,Int)]
restos n (x,i) = [(x `div` k,i) | k <- [1..n]]

-- (reparto1 n vs) es la lista formada por los n restos mayores
-- correspondientes a la lista de votos vs. Por ejemplo,
--    λ> reparto1 7 ejVotos
--    [(340000,1),(280000,2),(170000,1),(160000,3),(140000,2),(113333,1),
--     (93333,2)]
reparto1 :: Int -> [Int] -> [(Int,Int)]
reparto1 n vs =
    take n $ reverse $ sort (concatMap (restos n) (votosPartidos vs))

-- (reparto2 n vs) es el número de los partidos, cuyos votos son vs, que
-- obtienen los n escaños. Por ejemplo,
--    λ> reparto2 7 ejVotos
--    [1,2,1,3,2,1,2]
reparto2 :: Int -> [Int] -> [Int]
reparto2 n vs = map snd (reparto1 n vs)

-- (reparto n vs) es la lista de los pares formados por los números de
-- los partidos y el número de escaño que les corresponden al repartir n
-- escaños en función de la lista de sus votos. Por ejemplo,
--    λ> reparto 7 ejVotos
--    [(1,3),(2,3),(3,1)]
reparto :: Int -> [Int] -> [(Int,Int)]
reparto n vs =
    [(x,1 + length xs) | (x:xs) <- group (sort (reparto2 n vs))]