SHOW:
|
|
- or go back to the newest paste.
1 | module Main where | |
2 | import Data.List | |
3 | import Data.Ord | |
4 | ||
5 | -- For testing purpose | |
6 | import Test.QuickCheck | |
7 | import Test.QuickCheck.Gen | |
8 | import System.Random | |
9 | ||
10 | type Z = Integer | |
11 | type Pt = (Z,Z) | |
12 | type Dir = Pt | |
13 | type Cost = Z | |
14 | ||
15 | sumV :: [Pt] -> Pt | |
16 | sumV = foldr addV (0,0) | |
17 | ||
18 | addV :: Pt -> Pt -> Pt | |
19 | addV (x,y) (u,v) = (x+u,y+v) | |
20 | ||
21 | divV :: Pt -> Z -> Pt | |
22 | divV (x,y) d = (x `div` d,y `div` d) | |
23 | ||
24 | second :: (a,b,c) -> b | |
25 | second (_,y,_) = y | |
26 | ||
27 | third :: (a,b,c) -> c | |
28 | third (_,_,z) = z | |
29 | ||
30 | mean :: [Pt] -> Pt | |
31 | mean xs = sumV xs `divV` genericLength xs | |
32 | ||
33 | dir0 :: [Dir] | |
34 | dir0 = [(-1,1) ,(0,1) ,(1,1) | |
35 | ,(-1,0) ,(1,0) | |
36 | ,(-1,-1),(0,-1),(1,-1)] | |
37 | ||
38 | -- Tweaking this would result 2x speed-up | |
39 | restrict :: Dir -> [Dir] -> [Dir] | |
40 | restrict d ds = ds | |
41 | ||
42 | d :: Pt -> Pt -> Z | |
43 | d (x,y) (u,v) = max (abs (x-u)) (abs (y-v)) | |
44 | ||
45 | costAt :: [Pt] -> Pt -> Cost | |
46 | costAt xs p = sum $ map (d p) xs | |
47 | ||
48 | cand :: Pt -> [Dir] -> [Pt] | |
49 | cand p ds = map (addV p) ds | |
50 | ||
51 | step :: [Pt] -> (Pt,Cost,[Dir]) -> (Pt,Cost,[Dir]) | |
52 | step xs (p,c,ds) | |
53 | | c' < c = (p',c', restrict d ds) | |
54 | | otherwise = (p ,c , []) | |
55 | where | |
56 | (p',c',d) = minimumBy (comparing second) $ map (look xs p) ds | |
57 | ||
58 | look :: [Pt] -> Pt -> Dir -> (Pt,Cost,Dir) | |
59 | look xs p d = (p',costAt xs p',d) | |
60 | where p' = p `addV` d | |
61 | ||
62 | -- seems like a reasonable guess | |
63 | start :: [Pt] -> (Pt,Cost,[Dir]) | |
64 | start xs = (p0,c0,dir0) | |
65 | where | |
66 | p0 = mean xs | |
67 | c0 = costAt xs p0 | |
68 | ||
69 | ||
70 | opt :: [Pt] -> (Pt,Cost,[Dir]) | |
71 | opt xs = head $ dropWhile (not . null . third) $ iterate (step xs) $ start xs | |
72 | ||
73 | optDebug :: [Pt] -> (Bool,[(Pt,Cost,[Dir])]) | |
74 | optDebug xs = (check xs p,head ns : ms) | |
75 | where | |
76 | (ms,ns) = span (not . null . third) $ iterate (step xs) $ start xs | |
77 | (p,c,_) = head ns | |
78 | ------------------------------------------------- | |
79 | -- test code | |
80 | ------------------------------------------------- | |
81 | ||
82 | check :: [Pt] -> Pt -> Bool | |
83 | check xs p = costAt xs p <= minimum (map (costAt xs) (cand p dir0)) | |
84 | ||
85 | prop_opt :: [Pt] -> Bool | |
86 | prop_opt xs = let (p,c,_) = opt xs | |
87 | in check xs p | |
88 | ||
89 | rollDice :: IO Int | |
90 | rollDice = getStdRandom random | |
91 | ||
92 | randomPts :: Int -> IO [Pt] | |
93 | randomPts n = do rollDice | |
94 | gen <- getStdGen | |
95 | return $ unGen (vectorOf n arbitrary) gen 1000 | |
96 | ||
97 | main = do xs <- randomPts 100000 | |
98 | print $ optDebug xs | |
99 | ||
100 | sample0,sample1,sample2 :: [Pt] | |
101 | sample0 = [(0,0)] | |
102 | sample1 = [(0,0),(1,1)] | |
103 | sample2 = [(0,2),(1,2),(2,2) | |
104 | , (1,1) | |
105 | , (2,0) ] | |
106 | ||
107 | sample3 = [(0,3) | |
108 | ,(0,2),(1,2) | |
109 | ,(0,1),(1,1),(2,1) | |
110 | ,(0,0),(1,0),(2,0),(3,0)] | |
111 | ||
112 | ||
113 | sample4 = [(0,3) | |
114 | ,(0,2),(1,2) | |
115 | ,(0,1),(1,1),(2,1) | |
116 | ,(0,0),(1,0),(2,0),(3,0)] | |
117 | ||
118 | sample5 = [ (-3, 0), (-2, 0), (-1, 0), (0, 0), (10, 0), (50, 0) ] |