Я искал в Интернете различные решения проблемы n-queens в Haskell, но не смог найти ни одного, который мог бы проверять небезопасные позиции в O (1) раз, как тот, который вы храните массив для/диагоналей и один для\диагоналей.
Большинство решений, которые я нашел, просто проверяли каждую новую королеву против всех предыдущих. Что-то вроде этого: http://www.reddit.com/r/programming/comments/62j4m/nqueens_in_haskell/
nqueens :: Int -> [[(Int,Int)]]
nqueens n = foldr qu [[]] [1..n]
where qu k qss = [ ((j,k):qs) | qs <- qss, j <- [1..n], all (safe (j,k)) qs ]
safe (j,k) (l,m) = j /= l && k /= m && abs (j-l) /= abs (k-m)
Какой был бы лучший способ реализовать такой подход "O (1)" в Haskell? Я не ищу ничего "супер-оптимизированного". Только какой-то способ создать "эта диагональ уже используется?" массив в функциональном режиме.
UPDATE:
Спасибо за все ответы, ребята! Причина, по которой я первоначально задавал этот вопрос, заключается в том, что я решил решить более сложную проблему возврата. Я знал, как его решить на императивном языке, но не мог легко думать о чисто функциональной структуре данных, чтобы выполнять эту работу. Я понял, что проблема с королевой будет хорошей моделью (проблема с возвратом:):) для общей проблемы структуры данных, но это не моя реальная проблема.
Я действительно хочу найти структуру данных, которая позволяет O (1) произвольный доступ и содержит значения, которые либо находятся в "начальном" состоянии (свободная линия/диагональ, в случае n-queens), либо в "final" (занятая линия/диагональ), причем переходы (свободные для занятых) являются O (1). Это может быть реализовано с использованием изменяемых массивов на императивном языке, но я чувствую, что ограничение значений обновления только позволяет получить хорошую чисто функциональную структуру данных (в отличие от Quicksort, например, которая действительно хочет измененные массивы).
Я полагаю, что решение sth так же хорошо, как вы можете использовать неизменяемые массивы в Haskell, а функция "main" выглядит так, как я хотел:
-- try all positions for a queen in row n-1
place :: BoardState -> Int -> [[(Int, Int)]]
place _ 0 = [[]]
place b n = concatMap place_ (freefields b (n-1))
where place_ p = map (p:) (place (occupy b p) (n-1))
Основная проблема, похоже, заключается в нахождении лучшей структуры данных, поскольку Haskell Arrays имеет O (n) обновление. Другие приятные предложения не соответствуют мифическому О (1) святому Граалю:
- DiffArrays приближаются, но беспорядок в обратном направлении. Они на самом деле становятся супер медленными:(.
- STUArrays конфликтует с довольно функциональным подходом к backtracking, поэтому они отбрасываются.
- Карты и наборы имеют только O (log n).
Я не уверен, что есть решение в целом, но оно кажется многообещающим.
UPDATE:
Самая многообещающая структура данных, которую я нашел там, где Trailer Arrays. В основном Haskell DiffArray, но он мутирует назад, когда вы возвращаетесь назад.