fork download
  1. --import Data.List (minimumBy, findIndex)
  2. import Data.List (minimumBy, findIndex, find)
  3. import Data.Maybe (fromJust)
  4. import Data.Array
  5.  
  6. extendr ind xs =
  7. let splitxs = splitAt ind xs
  8. from = snd (head $ snd splitxs)
  9. toMove = last from
  10. toKeep = init from
  11. left = if null toKeep
  12. then []
  13. else [(sum toKeep, toKeep)]
  14. right = toMove : snd (head $ tail $ snd splitxs)
  15. in fst splitxs ++ left ++ [(sum right, right)] ++ tail (tail $ snd splitxs)
  16.  
  17. extendl ind xs =
  18. let splitxs = splitAt ind xs
  19. from = snd (head $ snd splitxs)
  20. toMove = head from
  21. toKeep = tail from
  22. right = if null toKeep
  23. then []
  24. else [(sum toKeep, toKeep)]
  25. left = snd (last $ fst splitxs) ++ [toMove]
  26. in init (fst splitxs) ++ [(sum left, left)] ++ right ++ tail (snd splitxs)
  27.  
  28. scanOne xs = scanOne' 1 [] where
  29. len = length xs
  30. scanOne' ind result
  31. | ind == len = result
  32. let splitxs = splitAt ind xs
  33. temp = (min (sum $ fst splitxs) (sum $ snd splitxs), ind)
  34. in scanOne' (ind + 1) (temp:result)
  35.  
  36. unlink ind x =
  37. let splitToUnlink = splitAt ind (snd x)
  38. left = (sum (fst splitToUnlink), fst splitToUnlink)
  39. right = (sum (snd splitToUnlink), snd splitToUnlink)
  40. in [left] ++ [right]
  41.  
  42. removeExtras currentMin xs = removeExtras' xs 0 [] where
  43. removeExtras' [] numRemoved result = (result, numRemoved)
  44. removeExtras' (y:ys) numRemoved result =
  45. if fst y - minimum (snd y) >= currentMin
  46. then let scanned = filter (\z -> fst z >= currentMin) $ scanOne (snd y)
  47. in if null scanned
  48. then removeExtras' ys numRemoved (result ++ [y])
  49. else let removed = unlink (snd $ head scanned) y
  50. in removeExtras' ys (numRemoved + 1) (result ++ removed)
  51. else removeExtras' ys numRemoved (result ++ [y])
  52.  
  53. maximize ind currentMin xs =
  54. if ind == 0
  55. then maximizeR' maximizeR
  56. else if ind == length xs - 1
  57. then maximizeL' maximizeL
  58. else maximizeRL
  59. where splitxs = splitAt ind xs
  60. maximizeR' variables = let vs = fst variables in
  61. if snd variables <= currentMin
  62. then (xs, 0)
  63. else (fst splitxs
  64. ++ [(sum (fst vs), fst vs)]
  65. ++ [(sum (snd $ snd vs), snd $ snd vs)]
  66. ++ drop 2 (snd splitxs)
  67. , snd variables)
  68. maximizeL' variables = let vs = fst variables in
  69. if snd variables <= currentMin
  70. then (xs, 0)
  71. else (init (fst splitxs)
  72. ++ [(sum (fst $ snd vs), fst $ snd vs)]
  73. ++ [(sum (fst vs), fst vs)]
  74. ++ tail (snd splitxs)
  75. , snd variables)
  76. maximizeRL =
  77. let leftRight = [maximizeL, maximizeR]
  78. best = max (snd $ head leftRight) (snd $ last leftRight)
  79. in if best /=0 && best <= currentMin
  80. then (xs, 0)
  81. else if snd (head leftRight) >= snd (last leftRight)
  82. then maximizeL' (head leftRight)
  83. else maximizeR' (last leftRight)
  84. maximizeR =
  85. if numVariations == 0
  86. then (([], ([],[])), 0)
  87. else let variationsR = map (\x -> splitAt x right) [1..numVariations]
  88. variations = map (\x -> minimum [sum (left ++ fst x), sum (snd x)]) variationsR
  89. maxVariations = maximum variations
  90. splitInd = fromJust (findIndex (==maxVariations) variations)
  91. splitR = variationsR!!splitInd
  92. newLeft = left ++ fst splitR
  93. in ((newLeft, splitR), maxVariations)
  94. where left = snd $ head $ snd splitxs
  95. right = snd $ head $ tail $ snd splitxs
  96. lenRight = length right
  97. numVariations =
  98. lenRight - length (foldr (\a b -> if sum b >= currentMin then b else a:b) [] right)
  99. maximizeL =
  100. if numVariations == 0
  101. then (([], ([],[])), 0)
  102. else let variationsL = map (\x -> splitAt x left) [lenLeft-1, lenLeft - 2..lenLeft - numVariations]
  103. variations = map (\x -> minimum [sum (fst x), sum (snd x ++ right)]) variationsL
  104. maxVariations = maximum variations
  105. splitInd = fromJust (findIndex (==maxVariations) variations)
  106. splitL = variationsL!!splitInd
  107. newRight = snd splitL ++ right
  108. in ((newRight, splitL), maxVariations)
  109. where splitxs = splitAt ind xs
  110. right = snd $ head $ snd splitxs
  111. left = snd $ last $ fst splitxs
  112. lenLeft = length left
  113. numVariations =
  114. lenLeft - length (foldl (\a b -> if sum a >= currentMin then a else b:a) [] left)
  115.  
  116. maxDiff m xs = extend (zip (map sum differences) differences) where
  117. differences = map (:[]) $ tail $ zipWith (-) xs ([0] ++ init xs)
  118. extend ys =
  119. let count = sum (map (\x -> length (snd x) - 1) ys)
  120. lastInd = length ys - 1
  121. lowestElem = minimumBy (\a b -> compare (fst a) (fst b)) ys
  122. lowestSum = fst lowestElem
  123. lowestInd = fromJust (findIndex (==lowestElem) ys)
  124. in if count < m
  125. then if lowestInd == 0
  126. then extend (extendr lowestInd ys)
  127. else if lowestInd == lastInd
  128. then extend (extendl lowestInd ys)
  129. else if fst (ys!!(lowestInd - 1)) <= fst (ys!!(lowestInd + 1))
  130. then extend (extendl lowestInd ys)
  131. else extend (extendr lowestInd ys)
  132. else let maximized = maximize lowestInd lowestSum ys
  133. in if snd maximized == 0
  134. then let removed = removeExtras lowestSum ys
  135. in putStrLn (
  136. show (foldr (\a b -> (head b - fst a) : b) [last xs] (fst removed))
  137. ++ "\nMinimum Difference: " ++ show lowestSum
  138. ++ "\n" ++ show (m - snd removed) ++ " Removals"
  139. ++ "\nOriginal Differences, Grouped:\n" ++ show (fst removed))
  140. else extend (fst maximized)
  141.  
  142. -- __j_random_hacker's stuff begins here
  143.  
  144. -- My algorithm from http://stackoverflow.com/a/15478409/47984.
  145. -- Oddly it seems to be much faster when I *don't* try to use memoisation!
  146. -- (I don't really understand how memoisation in Haskell works yet...)
  147. jrhMaxDiff m xs = fst $ fromJust $ find (\(x, y) -> snd x > snd y) resultPairsDesc
  148. where
  149. inf = 1000000
  150. n = length xs
  151. f i j =
  152. -- rawF i j =
  153. if i == n - 1
  154. then if j == 0
  155. then inf
  156. else 0
  157. else maximum [g i j d | d <- [0 .. min j (n - i - 2)]]
  158. -- f i j = (array ((0, 0), (n, m)) [((ii, jj), rawF ii jj) | ii <- [0 .. n], jj <- [0 .. m]]) ! (i, j)
  159. g i j d = min ((xs !! (i + d + 1)) - (xs !! i)) (f (i + d + 1) (j - d))
  160. resultsDesc = map (\i -> (i, f 0 i)) $ reverse [0 .. m]
  161. resultPairsDesc = zip resultsDesc (concat [(tail resultsDesc), [(-1, -1)]])
  162.  
  163. -- All following code is for looking for different results between my and groovy's algorithms.
  164.  
  165. -- The same as groovy's maxDiff, but returning only a (numDeletions, lowestSum) pair instead of printing out this (and more) info.
  166. pureMaxDiff m xs = extend (zip (map sum differences) differences) where
  167. differences = map (:[]) $ tail $ zipWith (-) xs ([0] ++ init xs)
  168. extend ys =
  169. let count = sum (map (\x -> length (snd x) - 1) ys)
  170. lastInd = length ys - 1
  171. lowestElem = minimumBy (\a b -> compare (fst a) (fst b)) ys
  172. lowestSum = fst lowestElem
  173. lowestInd = fromJust (findIndex (==lowestElem) ys)
  174. in if count < m
  175. then if lowestInd == 0
  176. then extend (extendr lowestInd ys)
  177. else if lowestInd == lastInd
  178. then extend (extendl lowestInd ys)
  179. else if fst (ys!!(lowestInd - 1)) <= fst (ys!!(lowestInd + 1))
  180. then extend (extendl lowestInd ys)
  181. else extend (extendr lowestInd ys)
  182. else let maximized = maximize lowestInd lowestSum ys
  183. in if snd maximized == 0
  184. then let removed = removeExtras lowestSum ys
  185. in ((m - snd removed), lowestSum)
  186. else extend (fst maximized)
  187.  
  188. -- Generate a list of all length-n lists containing numbers in the range 0 - d.
  189. upto :: Int -> Int -> [[Int]]
  190. upto 0 _ = [[]]
  191. upto n d = concat $ map (\x -> (map (\y -> (x : y)) (upto (n - 1) d))) [0 .. d]
  192.  
  193. -- Generate a list of all length-maxN or shorter lists containing numbers in the range 0 - maxD.
  194. generateAllDiffCombos :: Int -> Int -> [[Int]]
  195. generateAllDiffCombos 1 maxD = [[x] | x <- [0 .. maxD]]
  196. generateAllDiffCombos maxN maxD =
  197. (generateAllDiffCombos (maxN - 1) maxD) ++ (upto maxN maxD)
  198.  
  199. diffsToNums xs = scanl (+) 0 xs
  200.  
  201. generateAllCombos maxN maxD = map diffsToNums $ generateAllDiffCombos maxN maxD
  202.  
  203. -- generateAllCombos causes pureMaxDiff to produce an error with (1, [0, 0]) and (1, [0, 0, 0]) among others,
  204. -- so filter these out to look for more "interesting" differences.
  205. --generateMostCombos maxN maxD = filter (\x -> length x /= 2) $ generateAllCombos maxN maxD
  206. generateMostCombos maxN maxD = filter (\x -> length x > 4) $ generateAllCombos maxN maxD
  207.  
  208. -- Try running both algorithms on every list of length up to maxN having gaps of
  209. -- size up to maxD, allowing up to maxDel deletions (this is the M parameter).
  210. compareAllCombos maxN maxD maxDel =
  211. find (\(x, jrh, grv) -> jrh /= grv) $ map (\x -> (x, jrhMaxDiff maxDel x, pureMaxDiff maxDel x)) $ generateMostCombos maxN maxD
  212. -- show $ map (\x -> (x, jrhMaxDiff maxDel x, pureMaxDiff maxDel x)) $ generateMostCombos maxN maxD
  213.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
[1 of 1] Compiling Main             ( prog.hs, prog.o )

prog.hs:1:1: The function `main' is not defined in module `Main'
stdout
Standard output is empty