Вот что-то неоптимальное в Haskell, которое (как и многие из моих идей), вероятно, можно было бы еще лучше оптимизировать. Это выглядит примерно так:
- Отсортируйте массив (я получил интересные результаты, попробовав как по возрастанию, так и по убыванию)
- B N = первые N элементов массива
- B (i), для i > N = лучший кандидат; где (предполагая целые числа), если они оба меньше 1, кандидаты сравниваются по модулю их сумм; если они оба равны 1 или больше, по их суммам; и если только один кандидат больше 0, то этот кандидат выбирается. Если сумма кандидата равна 1, верните этого кандидата в качестве ответа. Кандидатами являются:
B (i-1), B (i-1)[2,3,4..N] ++ массив [i], B (i-1)[1,3,4 ..N] ++ массив [i]...B (i-1)[1,2..N-1] ++ массив [i]
B (i-2)[2,3, 4..N] ++ массив [i], B (i-2)[1,3,4..N] ++ массив [i]...B (i-2)[1,2..N -1] ++ массив [i]
...
B (N)[2,3,4..N] ++ массив [i], B (N)[1,3, 4..N] ++ массив [i]...B (N)[1,2..N-1] ++ массив [i]
Обратите внимание, что для той части массива, где числа отрицательные (в случае сортировки по возрастанию) или положительные (в случае сортировки по убыванию), шаг 3 можно выполнить сразу без вычислений.
Вывод:
*Main> least 5 "desc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(10,[-1000,600,300,100,10])
(0.02 secs, 1106836 bytes)
*Main> least 5 "asc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(50,[300,100,-200,-100,-50])
(0.02 secs, 1097492 bytes)
*Main> main -- 10000 random numbers ranging from -100000 to 100000
(1,[-106,4,-40,74,69])
(1.77 secs, 108964888 bytes)
Код:
import Data.Map (fromList, insert, (!))
import Data.List (minimumBy,tails,sort)
import Control.Monad.Random hiding (fromList)
array = [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
least n rev arr = comb (fromList listStart) [fst (last listStart) + 1..m]
where
m = length arr
r = if rev == "asc" then False else True
sorted = (if r then reverse else id) (sort arr)
listStart = if null lStart
then [(n,(sum $ take n sorted,take n sorted))]
else lStart
lStart = zip [n..]
. takeWhile (all (if r then (>0) else (<0)) . snd)
. foldr (\a b -> let c = take n (drop a sorted) in (sum c,c) : b) []
$ [0..]
s = fromList (zip [1..] sorted)
comb list [] = list ! m
comb list (i:is)
| fst (list ! (i-1)) == 1 = list ! (i-1)
| otherwise = comb updatedMap is
where updatedMap = insert i bestCandidate list
bestCandidate = comb' (list!(i - 1)) [i - 1,i - 2..n] where
comb' best [] = best
comb' best (j:js)
| fst best == 1 = best
| otherwise =
let s' = map (\x -> (sum x,x))
. (take n . map (take (n - 1)) . tails . cycle)
$ snd (list!j)
t = s!i
candidate = minimumBy compare' (map (add t) s')
in comb' (minimumBy compare' [candidate,best]) js
add x y@(a,b) = (x + a,x:b)
compare' a@(a',_) b@(b',_)
| a' < 1 = if b' < 1 then compare (abs a') (abs b') else GT
| otherwise = if b' < 1 then LT else compare a' b'
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100000,100000)
main = do
values <- evalRandIO (sequence (replicate (10000) rnd))
putStrLn (show $ least 5 "desc" values)
person
Community
schedule
28.06.2013