0votos

Spotify, tráfico de influencias en Haskell

por josejuan hace 6 años

La forma más sencilla de resolverlo eficientemente es usando programación lineal entera (obviando que es NP, claro).

Spotify presenta tres retos para quien quiera trabajar allí como programador. Uno de ellos es obtener una lista de beneficiarios sujeta a ciertas restricciones.

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
55
56
57
-- Usando GLPK, http://www.gnu.org/software/glpk/ 
import Data.List 
import Data.Maybe 
import Control.Monad 
import Data.LinearProgram 
import Data.LinearProgram.GLPK 
import qualified Data.Map as M 
 
-- Sólo por dar nombre a las varibles 
x e = "X" ++ show e 
 
-- Resuelve el problema de elegir el menor número de empleados 
solveEmployees :: [(Int, Int)] -> LP String Int 
solveEmployees es = execLPM $ do  setDirection Min 
                                  setObjective $ linCombination $ map (\e -> (1, x e)) emps 
                                  mapM_ (\(a, b) -> geqTo (varSum [x a, x b]) 1) es 
                                  mapM_ (\n -> setVarKind (x n) BinVar) emps 
                                  where emps = nub $ map fst es ++ map snd es 
 
-- Wrapper suponiendo que siempre hay solución (aquí siempre) 
getEmployees :: [(Int, Int)] -> IO [Int] 
getEmployees es = do 
  (_, Just (_, m)) <- glpSolveVars mipDefaults $ solveEmployees es 
  return $ map (read.tail.fst). M.toList. M.filter (==1) $ m 
 
 
-- Tráfico de influencias, intentaremos que el empleado 'e' vaya a la playa 
--       (da igual que sea de Estocolmo o de Londres) 
getEmployees' :: Int -> [(Int, Int)] -> IO [Int] 
getEmployees' e es = do 
  r <- getEmployees es 
  r' <- getEmployees $ filter (\(a, b ) -> a /= e && b /= e) es 
  return $ if length r == 1 + length r' then e: r' else r 
 
 
 
 
 
 
 
 
 
-- Test 
main = do 
  putStrLn $ "Input: " ++ show test2 
  putStrLn "Testing: solveEmployees" 
  r1 <- getEmployees test2 
  putStrLn $ show r1 
  putStrLn "Testing: solveEmployees' 2001" 
  r2 <- getEmployees' 2001 test2 
  putStrLn $ show r2 
 
test1 :: [(Int, Int)] 
test1 = [(1009, 2011), (1017, 2011)] 
 
test2 :: [(Int, Int)] 
test2 = [(1009, 2000), (1009, 2001), (1008, 2000), (1008, 2001)] 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.