Перетворити зразок в індекс


12

Ми кладемо кульки в фіксованому числі через бункера. Ці смітники починаються порожніми.

Empty bin (a=4): 0 0 0 0 

І по черзі ми додаємо кульки до бункерів.

0 0 0 1  or
0 0 1 0  or
0 1 0 0  or
1 0 0 0

Нам потрібен швидкий спосіб переключити всі можливі стани, які приймають бункери, без дублікатів і не пропускаючи жодних, і ми не хочемо перераховувати всі можливі бункери. Тому замість цього ми присвоюємо кожній бін-конфігурації індекс.

Індекс ми присвоюємо, сортуючи можливі конфігурації певним чином:

  1. Сортувати за зростанням за сумою: так спочатку 0 0 0 0, потім можливі конфігурації з додаванням 1 кулі, потім 2 тощо.
  2. Потім сортуйте кожну суму у порядку зростання від першого кошика до останнього:

    0 0 0 2
    0 0 1 1
    0 0 2 0 
    0 1 0 1
    0 1 1 0 
    0 2 0 0 
    etc
    
  3. Потім індекс присвоюється у порядку зростання за допомогою цього списку:

    0 0 0 0  -> 1
    0 0 0 1  -> 2
    0 0 1 0  -> 3
    0 1 0 0  -> 4
    1 0 0 0  -> 5
    0 0 0 2  -> 6
    0 0 1 1  -> 7
    0 0 2 0  -> 8
    0 1 0 1  -> 9
    0 1 1 0  -> 10
    0 2 0 0  -> 11 
    

Правила

Створіть функцію або програму, яка приймає список будь-якого розміру з негативними цілими числами та роздруковує або виводить її індекс. Ви можете припустити, що принаймні 2. Виграє найкоротший код. Ви можете використовувати 0-індексований вихід або 1-індексований, але вказати, який ви використовуєте. Примітка: всі приклади тут є 1-індексованими.

Приклад коду

Не гольф, в R:

nodetoindex <- function(node){
  a <- length(node)
  t <- sum(node)
  if(t == 0) return(1)

  index <- choose(t-1 + a, a)

  while(sum(node) != 0){
    x <- node[1]
    sumrest <- sum(node)
    if(x == 0){
      node <- node[-1]
      next
    }
    a <- length(node[-1])
    index <- index + choose(sumrest + a, a) - choose(sumrest - x + a, a)
    node <- node[-1]
  }
  return(index + 1)
} 

Тестові справи

10 10 10 10 -> 130571
3 1 4 1 5 9 -> 424407
2 9 -> 69
0 0 0 -> 1
0 0 1 -> 2
0 0 0 0 0 0 -> 1
1 0 0 0 0 1 -> 23

Як працює сортування за числовим значенням конкатенації, коли підрахунки мають різну кількість цифр?
TheBikingViking

@TheBikingViking хм, не думав про це, я змінив формулювання, щоб відобразити приклад коду та тестові випадки. У межах кожної суми конфігурації сортуються спочатку в першому біні, потім у другому тощо.
JAD

Відповіді:


3

Желе , 8 байт

S0rṗLSÞi

Спробуйте в Інтернеті!

Жорстоке рішення. Перший тест - це занадто багато для TIO, але я перевірив його локально на своєму ноутбуці. Другий тестовий випадок вимагає занадто багато оперативної пам’яті, навіть для мого настільного комп’ютера.

Як це працює

S0rṗLSÞi  Main link. Argument: A (array)

S         Compute the sum s of A.
 0r       Create the range [0, ..., s].
    L     Yield the length l of A.
   ṗ      Cartesian power; yield the array of all l-tuples over [0, ..., s], in
          lexicographical order.
     SÞ   Sort the l-tuples by their sums. The sorting mechanism is stable, so
          l-tuples with the same sum are still ordered lexicographically.
       i  Find the index of A in the generated array of tuples.

Приємно. Ваше зауваження щодо оперативної пам’яті нагадало мені джерело цього виклику. Для моєї дипломної роботи мені потрібно було перекинути всі можливі масиви на деяку a = 8 і якомога вище куль. Ідея перетворити масиви в індекси та просто перетворити цикл на них виникла саме з обмеження оперативної пам’яті: P
JAD

І тому приклад коду настільки виразний: P
JAD

1

Clojure, 152 байти

#(loop[v[(vec(repeat(count %)0))]i 1](if-let[r((zipmap v(range))%)](+ r i)(recur(sort(set(for[v v i(range(count v))](update v i inc))))(+ i(count v)))))

Не так просто, як я думав. Менш гольф-версія:

(def f (fn[t](loop[v[(vec(repeat(count t)0))]i 1]
               (if-let[r((zipmap v(range))t)](+ r i)
                 (recur (sort-by (fn[v][(apply + v)v]) (set(for[v v i(range(count v))](update v i inc))))
                        (+ i(count v)))))))

Петля за поточними станами vстворює хеш-карту від елементів vдо їх рангу, якщо знайдений стан, що шукається, його ранг повертається (+ кількість раніше переглянутих станів). Якщо не знайдено, тоді повторюється новий набір можливих станів.

О, насправді нам не потрібна спеціальна функція сортування, оскільки всі стани в кожному циклі мають однакову суму. Це не так повільно, як я очікував, оскільки [3 1 4 1 5 9]зайняло лише 2,6 секунди.


1

Математика, 50 байт

Порт Дженніса відповідь .

0~Range~Tr@#~Tuples~Length@#~SortBy~Tr~Position~#&

Безіменна функція, що приймає список цілих чисел як вхідне і повертає список глибини-2 з одним цілим числом як вихід; наприклад, вхід для останнього тестового випадку є, {1,0,0,0,0,1}а вихід - {{23}}.

Трохи незворушена версія:

Position[SortBy[Tuples[Range[0,Tr[#]],Length[#]],Tr],#]&

Часто ми можемо зберегти окремі байти в Mathematica, використовуючи позначення префікса ( function@nзамість function[n]) та позначення інфіксації ( a~function~bзамість function[a,b]). Це працює лише тоді, коли отриманий код добре поєднується з внутрішнім порядком пріоритетності Mathematica для застосування функцій. Я був частково вражений тут , що, з шістьма наборами квадратних дужок, він дійсно працював , щоб видалити всі з них і зберегти шість байтів з (приємніше bracketless) представленого коду.

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