
Minimum Sum of All Travel Times
By: a guest on
Feb 20th, 2012 | syntax:
Haskell | size: 2.74 KB | hits: 184 | expires: Never
module Main where
import Data.List
import Data.Ord
-- For testing purpose
import Test.QuickCheck
import Test.QuickCheck.Gen
import System.Random
type Z = Integer
type Pt = (Z,Z)
type Dir = Pt
type Cost = Z
sumV :: [Pt] -> Pt
sumV = foldr addV (0,0)
addV :: Pt -> Pt -> Pt
addV (x,y) (u,v) = (x+u,y+v)
divV :: Pt -> Z -> Pt
divV (x,y) d = (x `div` d,y `div` d)
second :: (a,b,c) -> b
second (_,y,_) = y
third :: (a,b,c) -> c
third (_,_,z) = z
mean :: [Pt] -> Pt
mean xs = sumV xs `divV` genericLength xs
dir0 :: [Dir]
dir0 = [(-1,1) ,(0,1) ,(1,1)
,(-1,0) ,(1,0)
,(-1,-1),(0,-1),(1,-1)]
-- Tweaking this would result 2x speed-up
restrict :: Dir -> [Dir] -> [Dir]
restrict d ds = ds
d :: Pt -> Pt -> Z
d (x,y) (u,v) = max (abs (x-u)) (abs (y-v))
costAt :: [Pt] -> Pt -> Cost
costAt xs p = sum $ map (d p) xs
cand :: Pt -> [Dir] -> [Pt]
cand p ds = map (addV p) ds
step :: [Pt] -> (Pt,Cost,[Dir]) -> (Pt,Cost,[Dir])
step xs (p,c,ds)
| c' < c = (p',c', restrict d ds)
| otherwise = (p ,c , [])
where
(p',c',d) = minimumBy (comparing second) $ map (look xs p) ds
look :: [Pt] -> Pt -> Dir -> (Pt,Cost,Dir)
look xs p d = (p',costAt xs p',d)
where p' = p `addV` d
-- seems like a reasonable guess
start :: [Pt] -> (Pt,Cost,[Dir])
start xs = (p0,c0,dir0)
where
p0 = mean xs
c0 = costAt xs p0
opt :: [Pt] -> (Pt,Cost,[Dir])
opt xs = head $ dropWhile (not . null . third) $ iterate (step xs) $ start xs
optDebug :: [Pt] -> (Bool,[(Pt,Cost,[Dir])])
optDebug xs = (check xs p,head ns : ms)
where
(ms,ns) = span (not . null . third) $ iterate (step xs) $ start xs
(p,c,_) = head ns
-------------------------------------------------
-- test code
-------------------------------------------------
check :: [Pt] -> Pt -> Bool
check xs p = costAt xs p <= minimum (map (costAt xs) (cand p dir0))
prop_opt :: [Pt] -> Bool
prop_opt xs = let (p,c,_) = opt xs
in check xs p
rollDice :: IO Int
rollDice = getStdRandom random
randomPts :: Int -> IO [Pt]
randomPts n = do rollDice
gen <- getStdGen
return $ unGen (vectorOf n arbitrary) gen 1000
main = do xs <- randomPts 100000
print $ optDebug xs
sample0,sample1,sample2 :: [Pt]
sample0 = [(0,0)]
sample1 = [(0,0),(1,1)]
sample2 = [(0,2),(1,2),(2,2)
, (1,1)
, (2,0) ]
sample3 = [(0,3)
,(0,2),(1,2)
,(0,1),(1,1),(2,1)
,(0,0),(1,0),(2,0),(3,0)]
sample4 = [(0,3)
,(0,2),(1,2)
,(0,1),(1,1),(2,1)
,(0,0),(1,0),(2,0),(3,0)]
sample5 = [ (-3, 0), (-2, 0), (-1, 0), (0, 0), (10, 0), (50, 0) ]