Створіть Сколемські послідовності


10

Сколемські послідовності

Послідовність Сколема - це послідовність 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...у вашому питанні? Це фрагмент коду, якщо так, то яка мова це?
PhiNotPi

2
Чому перший елемент у вашому висновку 0? Якщо ви збираєтесь визнати 0правильним вхід, то вихід повинен бути 1.
Пітер Тейлор

1
Деякі (включаючи мій код) вважають, що є нульові порожні послідовності. Якщо 1 почуває себе краще, поверніть це.
виставка

2
AFAIK у будь-якому контексті ви припускаєте, що є одна і лише одна порожня послідовність / нульовий об'єкт / порожній набір і т.д. / функція-до / з-порожнього-набору / порожній графік / все інше.
Бакуріу

1
@boothby, ти щойно назвав Кнут дурнем?
Пітер Тейлор

Відповіді:


8

GolfScript, 48 46 символів

:b,1,{)2\?){{.2$&!{.2$|@@}*.+.4b?<}do;;}+%}@/,

Більш швидка версія ( спробуйте в Інтернеті ) - працює досить розумно, наприклад, n=8займає близько двох секунд. І обраний підхід займає дійсно мало символів.

Ця версія також працює з бітовими масками. Він будує можливий масив результатів від 1 вгору, тобто для n=3:

1: 000011        000110 001100 011000 110000
2: 010111 101011 101110        011101 110101 111010

Хоча деякі результати (наприклад, 000011) мають два можливі продовження, інші (тобто 001100) не мають жодного і видаляються з масиву результатів.

Пояснення коду:

:b           # save the input into variable b for later use
,            # make the list 0..b-1 (the outer loop)
1,           # puts the list [0] on top of the stack - initially the only possible
             # combination
{)           # {...}@/ does the outer loop counting from i=1 to b
  2\?)       # computes the smalles possible bit mask m=2^i+1 with two bits set 
             # and distance of those equal to i (i.e. i=1: 11, i=2: 101, ...)
  {          # the next loop starts with this bitmask (prepended to code via
             # concatination {...}+
             # the loop itself iterates the top of the stack, i.e. at this point 
             # the result array                 
             # stack here contains item of result array (e.g. 00000011)
             # and bitmask (e.g. 00000101)
    {        # the inner-most loop tries all masks with the current item in the result set
      .2$&!  # do item and result set share not single bit? then - {...}*
      {
        .2$| # then generate the new entry by or-ing those two
        @@   # push it down on the stack (i.e. put working items to top)
      }*
      .+     # shift the bit mask left by one
      .4b?<  # if still in the range loop further
    }do;;    # removes the remainders of the loop (i.e. item processed and mask)
  }+%        # stack now contains the new result array
}@/
,            # length of result array, i.e. the number of Skolem sequences

Прийняття швидше пов'язаних рішень.
кабінка

6

J вираз, 47 символів

 +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y

Приклад:

    y=:5
    +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y
10

y=:5На моїй машині потрібно 30 секунд .

алгоритм настільки ж повільний, як може бути:

  • ~.(i.!+:y)A.,~>:i.yгенерує кожну перестановку 1 2 .. y 1 2 .. yта видаляє повторювані записи
  • ((=&{:+.2-#@])#;.2)\"1 обчислює:
    • (...)\"1 для кожного префіксу кожного рядка:
      • #;.2 підраховує елементи перед кожним виникненням останнього елемента
      • #@] підраховує кількість відліків (тобто кількість випадків останнього елемента)
      • =&{: визначає "рівність" "" "" останній елемент "s списку відліку та вихідного списку.
      • +.є логічним АБО. =&{:+.2-#@]читає "або останні елементи [у списку підрахунків та вихідний список] рівні, або є лише один елемент [у списку рахунків], а не два".
  • */"1 множиться (логічно І) на рядки таблиці умов, визначаючи, які перестановки є послідовностями Сколема.
  • +/ підсумовує ці і нулі разом.

6

GolfScript (46 символів)

:&1,\,{0,2@)?)2&*{2${1$^}%@+\2*}*;+}/{4&?(=},,

Це вираз, який приймає дані про стек. Щоб перетворити його на повну програму, яка приймає дані про 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 символів як вираз), зберігаючи петлі максимально обмеженими і фільтруючи проміжні зіткнення:

~:&1,\,{0,\).2\?)2&*@-{.{[\].~^.@~+<{;}*}+3$%@+\2*}*;\;}/{4&?(=},,

Блін. Просто коли я подумав, що моє рішення на 48char J було досить хорошим, щоб бути розміщеним.
Джон Дворак

Блін. Наш 47-символьний краватку тривав не дуже довго. +1
Джон Дворак

5

GolfScript, 49 символів

~:/..+?:d(,{d+/base(;:w;/,{.w?)w>1$?=},,/=},,/1=+

Очікує число nна STDIN. Це код-гольф - не спробуйте код nбільше 5.


О, не більше 5?
виставка

@boothby Це була перша, пряма спроба. Нам часто доводиться приймати швидкість рішення щодо розміру - і код-гольф приблизно розміром. Тому я також додав швидку версію - яка спочатку була набагато довшою, але зараз ще коротшою.
Говард

0

Шавлія, 70

Це трохи коротше мого оригіналу.

sum(1for i in DLXCPP([(i-1,j,i+j)for i in[1..n]for j in[n..3*n-i-1]]))

Як це працює:

Враховуючи матрицю 0/1, точна проблема покриття для цієї матриці полягає в пошуку підмножини рядків, що сума (як цілих чисел) вектору all-one. Наприклад,

11001
10100
01001
00011
00010

має рішення

10100
01001
00010

Мій улюблений підхід до проблем полягає в тому, щоб привести їх до точної проблеми прикриття. Сколемські послідовності ефективно полегшують це. Я роблю точну проблему покриття, коли рішення знаходяться в біекції з послідовностями Сколема довжиною 2n. Наприклад, ряд проблем для n=6є

  a   |  b  
001000|001001000000 # S[b] = S[b+a+1] = a

де позиція 1 a < nозначає, що символ aвикористовується. Решта позицій відповідають фактичним місцям у послідовності. Точний обкладинка відповідає кожному символу, який використовується точно один раз, і кожне місце заповнюється рівно один раз. За побудовою будь-який символ kу місці знаходиться на kвідстані від свого партнера.

У Sage DLXCPPце реалізація "танцювальних зв'язків" - вона вирішує точну проблему обкладинки виключно витончено. Це один з моїх улюблених алгоритмів коли-небудь, і перебування прямо на поверхні в Sage робить комбінаторне перерахування радістю.


Нічого собі, танцювальне посилання. Використання len(list(...))дозволить заощадити 4 символи.
Рей

@Ray Мій комп'ютер просто загине, якби я обчислив len(list(...))n = 16. І це б зовсім знищило час виконання.
виставка

Це правильно, тому що перетворення генератора в список коштувало багато пам'яті.
Рей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.