Сколем последовательности
Последовательность Сколема - это последовательность 2n
чисел, где каждое число i
между 1
и n
встречается ровно дважды, а расстояние между двумя вхождениями i
составляет ровно i
шаги. Вот несколько примеров последовательностей Сколема:
1 1
1 1 4 2 3 2 4 3
16 13 15 12 14 4 7 3 11 4 3 9 10 7 13 12 16 15 14 11 9 8 10 2 6 2 5 1 1 8 6 5
Следующие последовательности не являются последовательностями Сколема:
1 2 1 2 (The distance between the 1's is 2, not 1)
3 1 1 3 (The number 2 is missing)
1 1 2 1 1 2 (There are four 1's)
Задача
Напишите программу, функцию или выражение для подсчета количества всех последовательностей Сколема заданной длины. Более конкретно, ваш ввод - целое число n
, а вывод - количество последовательностей Сколема длины 2n
. Эта последовательность имеет запись OEIS . Для n = 0
, вы можете вернуть либо 0
или 1
. В первые несколько значений, начиная с 0
, являются
0, 1, 0, 0, 6, 10, 0, 0, 504, 2656, 0, 0, 455936, 3040560, 0, 0, 1400156768
Правила и оценки
Это код гольф. Формат вывода слабый в пределах разумного.
0, 1, 0, 0, 6...
в твоем вопросе? Это фрагмент кода, если так, то что это за язык?0
? Если вы собираетесь признать0
допустимым ввод, то вывод должен быть1
.Ответы:
GolfScript,
4846 символовБолее быстрая версия ( попробуйте онлайн ) - работает достаточно быстро, например,
n=8
занимает около двух секунд. И выбранный подход требует очень мало персонажей.Эта версия также работает с битовыми масками. Он строит массив возможных результатов от 1 и выше, то есть для
n=3
:Хотя некоторые результаты (например, 000011) имеют два возможных продолжения, другие (например, 001100) не имеют ни одного и удаляются из массива результатов.
Пояснение к коду:
источник
J выражение, 47 символов
Пример:
Занимает около 30 секунд
y=:5
на моей машине.алгоритм работает настолько медленно, насколько это возможно:
~.(i.!+:y)A.,~>:i.y
генерирует каждую перестановку1 2 .. y 1 2 .. y
и удаляет повторяющиеся записи((=&{:+.2-#@])#;.2)\"1
вычисляет:(...)\"1
для каждого префикса каждой строки:#;.2
считает элементы перед каждым вхождением последнего элемента#@]
подсчитывает количество отсчетов (то есть количество вхождений последнего элемента)=&{:
определяет "равенство" "из" последнего элемента "списка счетчиков и исходного списка.+.
это логическое ИЛИ.=&{:+.2-#@]
читает "либо последние элементы [в списке счетчиков и исходном списке] равны, либо в списке счетчиков есть только один элемент, а не два".*/"1
умножает (логическое И) на строки таблицы условий, определяя, какие перестановки являются последовательностями Сколема.+/
суммирует единицы и нули вместе.источник
GolfScript (46 символов)
Это выражение, которое принимает данные в стеке. Чтобы превратить его в полноценную программу, которая принимает ввод в stdin, добавьте
~
Это довольно неэффективно - большая часть экономии, которую я сэкономил при игре в гольф по сравнению с 56 безгольфовыми символами, заключалась в расширении диапазона петель способами, которые не дают неправильных результатов, но делают подсчет отходов.
Подход - побитовая маскировка декартовых произведений. Например, (используя двоичный код для масок) для
n=4
негольфированного кода вычислите xor каждого элемента в декартовом произведении[00000011 00000110 ... 11000000] x [00000101 00001010 ... 10100000] x ... x [00010001 ... 10001000]
. Любой результат с 8 битами может быть достигнут только с помощью неперекрывающихся масок.Чтобы оптимизировать размер, а не скорость, код накапливает частичные продукты (
S1 u S1xS2 u S1xS2xS3 ...
) и превращает каждый продукт в2n
элементы, а не только в те,2n-1-i
которые действительно могут внести вклад в правильную последовательность.скорость
Гольф-версия работает
n=5
на моем компьютере в течение 10 секунд и более 5 минутn=6
. Оригинальная версия без игрыn=5
в гольф вычисляется менее чем за секунду иn=6
примерно за 1 минуту. С простым фильтром промежуточных результатов, он может вычислитьn=8
за 30 секунд. Я набрал в нем 66 символов (в качестве программы - 65 символов в качестве выражения), сохранив как можно более ограниченные циклы и отфильтровывая промежуточные столкновения:источник
GolfScript, 49 символов
Ожидает число
n
на STDIN. Это код-гольф - не пытайтесь использовать кодn
больше 5.источник
Мудрец, 70
Это немного короче моего оригинала.
Как это работает:
Учитывая матрицу 0/1, точная проблема покрытия для этой матрицы состоит в том, чтобы найти подмножество строк, которые суммируют (как целые числа) с вектором всех единиц. Например,
есть решение
Мой любимый подход к задачам - привести их к точной проблеме прикрытия. Сколем последовательности эффективно способствуют этому. Я делаю точную проблему покрытия, где решения находятся в биекции с последовательностями Сколема длины
2n
. Например, строка задачи дляn=6
являетсягде 1 в положении
a < n
означает, что символa
используется. Остальные позиции соответствуют фактическим местоположениям в последовательности. Точное покрытие соответствует каждому символу, используемому ровно один раз, и каждое местоположение заполняется ровно один раз. По построению, любой символk
в локации находится наk
расстоянии от своего партнера.В Sage
DLXCPP
это реализация «танцующих звеньев» - она решает точную проблему покрытия исключительно изящным способом. Это один из моих любимых алгоритмов, и нахождение в Sage на самом деле делает комбинаторное перечисление радостью.источник
len(list(...))
спасет 4 символа.len(list(...))
для n = 16. И это полностью убило бы время выполнения.