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
1 |
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,
1 2 3 4 |
ghci> reparto 7 [340000,280000,160000,60000,15000] [(1,3),(2,3),(3,1)] ghci> 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
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] -- ghci> 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, -- ghci> 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, -- ghci> 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, -- ghci> 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, -- ghci> 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, -- ghci> 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))] |
Una pequeñísima mejora: