Деревья Фактора Декодирования

11

В случае, если вы пропустили деревья кодирования факторов , вот определение дерева факторов:

  • Пустая строка равна 1.
  • Конкатенация представляет собой умножение.
  • Число n, заключенное в круглые скобки (или любые парные символы), представляет n- е простое число, где 2 - первое простое число.
    • Обратите внимание, что это делается рекурсивно: n- е простое число - это дерево факторов для n в скобках.
  • Коэффициенты числа должны быть упорядочены от наименьшего к наибольшему.

Например, вот деревья факторов от 2 до 10:

()
(())
()()
((()))
()(())
(()())
()()()
(())(())
()((()))

Эта задача использует аналогичный формат; однако, эта задача состоит в том, чтобы декодировать эти структуры.

Тестовые случаи

Бесстыдно похищенный перепрофилирован из последнего вызова.

В дополнение к 9 выше ...

()()((()))((())) => 100
(()(()(()))) => 101
(()())(((())))(()(())) => 1001
(((((((()))))))) => 5381
(()())((((()))))(()()(())(())) => 32767
()()()()()()()()()()()()()()() => 32768

правила

  • Парные символы на входе - это выбор скобок, скобок, скобок или угловых скобок. Я могу разрешить другие форматы (например, теги XML), если спросят.
  • Вы должны иметь возможность обрабатывать Деревья Факторов для любого числа от 2 до 2 15 или 32768.
  • Поскольку это , выигрывает самый короткий ответ в байтах.
Нисса
источник

Ответы:

9

Wolfram Language (Mathematica) , 52 45 байт

ToExpression@*StringReplace[{"["->"Prime[1"}]

Попробуйте онлайн!

Ввод использует скобки.

Преобразует входные данные в выражение Mathematica, которое вычисляет результат. Мы делаем это просто путем замены [на Prime[1. Это работает, потому что конкатенация - это умножение в Mathematica.

Мартин Эндер
источник
8

Пролог (SWI) , 134 128 127 124 байтов

Этот ответ является частью сотрудничества между мной и 0 '. Мы оба работали над этим вместе, единственная причина, по которой я публикую это, в том, что я выиграл «Рок, бумага, ножницы».

\Q-->{Q=1};"(",\N,")",\B,{findnsols(N,I,(between(2,inf,I),\+ (between(3,I,U),0=:=I mod(U-1))),L)->append(_,[Y],L),Q is Y*B}.

Попробуйте онлайн!

объяснение

Этот ответ является прекрасным примером того, что делает гольф в прологе веселым.


Этот ответ использует мощную систему Prologs для определенных грамматик. Вот наша грамматика немного раскололась.

head(1)-->[].
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
prime(N,Y):-
  findnsols(N,I,(
    between(2,inf,I),
    isprime(I)
  ),L),
  append(_,[Y],L),!.

Первое правило построения:

head(1)-->[].

Это говорит Прологу, что пустая строка соответствует 1.

Наше второе правило построения немного сложнее.

head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.

Это говорит нам о том, что любая непустая строка содержит скобки вокруг предложения с теми же правилами, справа от предложения с теми же правилами.

Это также говорит нам, что значение этого условия ( Q) следует правилу:

{prime(N,Y),Q is Y*B}

Разбивая это, Qэто произведение 2 чисел Yи B. Bэто просто значение предложения слева и Yэто Nпростое число, где Nэто значение предложения в скобках.

Это правило охватывает оба правила формирования дерева факторов

  • Умножение конкатенации
  • Вложение занимает n-е простое число

Теперь для определения предикатов. В негольфированной версии присутствуют два предиката (в моем собственном коде я переместил цепочку предикатов вперед). Здесь есть два соответствующих предиката isprime/1, которые соответствуют простому числу и prime/2, которые, учитывая Nи Y, соответствуют тогда, когда Yэто Nпростое число. Сначала мы имеем

isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).

Это работы довольно стандартного определения первичности, мы настаиваем на том, что между 2 и 2 I, включая 2, нет Iделения, но это не делит I.

Следующий предикат также довольно прост

prime(N,Y):-
  findnsols(N,I,(
    between(2,inf,I),
    isprime(I)
  ),L),
  append(_,[Y],L),!.

Мы используем, findnsolsчтобы найти первые Nчисла, которые являются простыми, затем мы возвращаем последнее. Хитрость в том, что хотя findnsolsне гарантируется поиск наименьших N простых чисел, из-за способа обработки SWI betweenвсегда найдутся меньшие простые числа. Это, однако, означает, что мы должны сократить, чтобы не найти больше простых чисел.


Гольфы

Мы можем переслать причину в нашем коде дважды. Так isprimeкак используется только один раз, его определение может быть перемещено внутри prime. Следующим является перемещение primeнепосредственно внутри DCG, однако, поскольку мы используем врезку, primeчтобы не findnsolsсоздавать слишком много простых чисел, у нас есть небольшая проблема. Cut, разрезает весь DCG вместо того, что мы хотим. После небольшой копки документации мы обнаружили, что она once/1может быть использована только для вырезания этой части, но не всей DCG. Однако, больше копания документации показало, что ->оператор мог также использоваться, чтобы выполнить подобную задачу. ->Оператор примерно эквивалентен ,!,поэтому мы переместили наш разрез на другую сторону append/3и заменить его ->.

В предикатах (и правилах) SWI-Prolog операторы могут быть заданы как имена, что позволяет нам убрать обычно необходимые скобки. Таким образом, мы можем сохранить 6 байтов, вызывая правило \.

Специальный охотник за гарфами
источник
1

JavaScript (ES6), 98 байт

Вдохновленный ответом Нотьягана на Python . Превращает входное выражение в огромную и безобразную исполняемую строку.

s=>eval(s.split`)(`.join`)*(`.split`(`.join`(g=(n,k)=>(C=d=>n%--d?C(d):k-=d<2)(++n)?g(n,k):n)(1,`)

Слияние Cи gфункции в один может сэкономить несколько байт, но для этого потребуется еще больше рекурсии.

Контрольные примеры

Arnauld
источник