Кратчайшее представление числа недогрузки

13

Ароматный текст

Основанный на стеке esolang Underload имеет некоторые интересные связи с функциональным программированием. Одним из них является обработка числового типа данных - подобно лямбда-исчислению, вы представляете натуральное число N функцией, которая выполняет действие N раз.

Для простоты мы рассмотрим только следующее подмножество команд недогрузки:

  • : - Эта команда дублирует верхний элемент в стеке.
  • * - Эта команда объединяет два верхних элемента в стеке в один элемент.

Определим НЕДОГРУЗКИ цифру N в виде строки :и *, при исполнении, потребляйте верхний элемент в стеке, и производят N копий этого элемента объединяются вместе. Несколько примеров:

  • Нет цифр недогрузки 0, -1, 1/2, π.
  • Пустая строка является цифрой недогрузки 1, поскольку она не затрагивает стек.
  • :*является цифрой недогрузки 2, потому что она дублирует верхний элемент, а затем объединяет эти две копии в один элемент: (A):*= (A)(A)*= (AA).
  • ::**является цифрой недогрузки 3: (A)::**= (A)(A):**= (A)(AA)*= (AAA).
  • :::*** является цифрой недогрузки 4.
  • :*:*также цифра недогрузки 4: (A):*:*= (AA):*= (AA)(AA)*= (AAAA).

В общем, вы обнаружите, что если Mи Nявляются числами недогрузки M и N, то :N*это число N + 1 и MNэто число M × N.

Соревнование

Ваша задача - написать самую короткую программу (с вводом по STDIN) или функцию (с вводом через аргумент), которая генерирует самое короткое представление цифры Underload для его ввода в виде строки. То есть, если вход является положительным натуральным числом N> 1, вы должны создать цифру недогрузки N, длина которой в символах меньше или равна длине любой другой цифры недогружения N.

Образцы входов и выходов: («Вход - OUTPUT.»)

  • 1 - .
  • 2 - :*.
  • 5 - ::*:**(2 × 2 + 1).
  • 7 - ::*::***(2 × 3 + 1) или :::**:**(3 × 2 + 1).
  • 33 - ::*:*:*:*:**(2 × 2 × 2 × 2 × 2 + 1).
  • 49 - ::*:*:*:*::***(16 × 3 + 1, длина 14), но не ::*::***::*::***(7 × 7, длина 16).

Если ввод не является положительным натуральным числом, вы можете вернуть ошибку, вызвать неопределенное поведение или даже не завершиться. Объяснение вашего метода поиска ответа приветствуется.

Применяются стандартные ограничения лазейки: никаких дополнительных входных данных, никаких веб-запросов, выходное / возвращаемое значение должно быть именно ответом, а не бесконечным случайным потоком символов :и *т. Д.

algorithmshark
источник
@ Geobits Я ничего не сказал о времени выполнения, так что, пока вы можете доказать, что он в конечном итоге даст правильный ответ, вы в порядке.
алгоритмистика
2
Эта проблема относится к сложению цепей; в частности, длина правильного ответа для ввода x- это то, 2*A117498(x)где A117498 дает оптимальную комбинацию двоичных и факторных методов для нахождения цепочки сложений.
Питер Тейлор

Ответы:

4

GolfScript ( 61 60 55 54 53 символа)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

Это менее сложно, чем моя предыдущая версия, и использует немного другой подход, но это все еще грубая сила. Мы знаем, что ':'X*'*'X*+это подходящее решение, поэтому, если мы сгенерируем все хорошо сбалансированные строки до этой длины и выберем самую короткую, которая оценивает правильную вещь, мы можем быть уверены, что найдем ее.

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

Спасибо Говарду, из решения которого я украл пару твиков с 1 символом.

Питер Тейлор
источник
Ха-ха, ввод 3 требует более трех секунд для выполнения в веб-интерпретаторе. Гольф во всей красе.
алгоритмистика
@algorithmshark, вы можете немного ускорить его с помощью дедупликации. Вставьте .&сразу после внутреннего цикла (то есть между ~}%и }*.
Питер Тейлор
4

GolfScript ( 54 53 символа)

Это подход, который соответствует духу Говарда (строит строки, которые оценивают правильное значение и выбирает самое короткое, а не грубую силу через строки-кандидаты, чтобы найти те, которые оценивают правильное значение), но достаточно отличается, на мой взгляд это относится к отдельному ответу.

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

Демонстрационная версия онлайн недоступна, потому что она работает с ошибочной версией переводчика.

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=
Питер Тейлор
источник
Можно было бы сбрить один замену 3+с )(используя тот факт , что []0=листы ничего в стеке) , если это не было то , что []2>приводит к ошибке.
Питер Тейлор
[]2>дает []без ошибок.
Говард
@ Ховард, ну, у golfscript.apphb.com должна быть установлена ​​старая версия. Но оказывается, что я был неправ, потому что эта замена приводит к неправильному выводу для ввода '1'.
Питер Тейлор
Что вы можете исправить с помощью ((=вместо -1=.
Говард
И golfscript.apphb.com действительно использует старую версию, пример с вложенными циклами не работает.
Говард
4

Python 2,7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

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

Примечания:
i и n / i являются двумя факторами n. ... и ... или ... замена ... если ... еще ... не работает, потому что '' оценивается как ложное. min строк дает одну из самых коротких строк. Python 2.7 сохраняет 1 символ, используя / вместо //.

Редактировать: перенес базовый регистр в конец выражения, что позволило мне использовать ... и ... или ... и сбрить пару пробелов.

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

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'
isaacg
источник
1
« min of strings дает одну из самых коротких строк » не верно, если вы не укажете необязательный аргумент key=len. Это дает лексикографически раннюю строку. ( Пример ). поскольку'*' < ':' это означает, что у вас есть склонность к решениям с участием степеней 2, но всегда ли они самые короткие?
Питер Тейлор
1
Ответ: на самом деле смещение более сложное, но оно не всегда дает правильный ответ. Наименьший контрпример u(33), для которого сортировка лексикографически дает 14 символов, ::**::*::*:***но сортировка по длине дает 12 символов::*:*:*:*:**
Питер Тейлор,
1
Я никогда не знал этого о сравнении строк в Python. Я обновил свой ответ.
Исаак
3

GolfScript, 63 58 56 символов

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

Код принимает входные данные в STDIN и печатает результат.

Примеры:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

Вы можете проверить свои собственные случаи онлайн .

Говард
источник
Ух ты, я думал, что подход, основанный на факторинге, будет немного длиннее, чем подход грубой силы.
Питер Тейлор
@PeterTaylor Я тоже так думал, но оказалось, что это не так. Более того, моё решение о грубой силе было немного длиннее, чем у вас ;-)
Говард,
Не могли бы вы объяснить, что делает каждая часть? Я могу только следить за :x(=битой. Также +1 за возможность пробежать 49 за разумное количество времени.
алгоритмистика
@algorithmshark Я все еще работаю над решением, поэтому оно все еще может сильно измениться (как это только что произошло). Преимущественно, часть x,2>{x\%!},дает все истинные делители x, {.v=x@/v=+}/затем объединяет решения для dи x/dдля всех делителей d. {,}$сортирует их по длине и 0=берет самые короткие из них (плюс начальный :(x-1)*регистр).
Говард
2

Brachylog 2 , 30 (возможно, в конечном итоге 26) байтов, языковые проблемы постдат

Вот функция, которая работает с текущей реализацией Brachylog 2 (и возвращает список кодов символов, потому что у текущей реализации есть некоторые проблемы с обработкой строк):

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

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

Язык все еще очень новый. Вот 26 байт версия программы, которая должна работать в соответствии со спецификацией, но использует некоторые невыполненные функции и, следовательно, еще не действительна, но, возможно, будет в будущем (это также еще менее эффективно):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

объяснение

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

Основная идея довольно проста: мы чередуем разложение числа на (1 или более) факторов (необязательно простые факторы, но факторы 1 не допускаются) и выражение каждого из них как 1 + (представление, полученное из рекурсивного вызов). Это гарантирует поиск во всех возможных представлениях числа Underload числа (мы можем применить этап умножения «два раза подряд», умножив вместе более 2 чисел, и ступень приращения дважды в строке, разделив их с этапом умножения, который умножает вместе только один номер). Нам не нужен явный базовый случай, потому что разложение 1 на простые множители дает нам пустой список, и, таким образом, мы строим его со стадией умножения, которая умножает нулевые числа вместе.

Программа довольно неэффективна, особенно потому, что подсказка о порядке оценки, которую я дал (генерировать ответы от кратчайшего до самого длинного с точки зрения размера конечного результата), хотя и решает «самую короткую» часть вопроса, не так уж велика с точки зрения на самом деле сделать программу быстро (гораздо больше полезный совет - «генерировать только самый короткий ответ на каждой рекурсивной стадии», но это занимает больше байтов…). Кроме того, ḋp~c×ᵐкаждый из них может генерировать мультипликативные разделы по несколько раз, заставляя программу выполнять много лишней работы.


источник
0

J - 81 символ

Для потомков это было лучшее, что я мог сделать в J.

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

Мы создаем список результатов, начиная с двух пустых строк (это ,~ и a:) и представляющих 0 (никогда не использовался) и 1, а затем перебираем глагол над ними (хитрое использование ловушек, поездов и &), который добавляет кратчайшее представление следующего числа.

Фактический глагол, который мы повторяем, использует длину списка как показатель того, над каким числом мы работаем. Сначала мы разбиваем это число на пары факторов (#(#~]-:"1<.)@(],.%)2}.i.@# ) и извлекаем каждую пару, извлекая из массива ( {~). Мы превращаем каждую из этих пар (их может быть 0, если число простое) в одну строку ( <@;"1).

Затем мы добавляем в этот список запись для предыдущего результата, заключенную в квадратные скобки :и *, и сортируем этот список по length ( (/:#&>)). Наконец, мы берем первый результат из этого list ( 0{) и добавляем его в конец базового массива ( [,). Когда цикл завершен итерацией, у нас есть список длины на 2 больше входного, начиная с 0. Так что мы должны вернуть строку, следующую за последней ( _2{::).

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539
algorithmshark
источник
0

Желе , 33 байта, языковые проблемы

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

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

Простое решение для грубой силы.

объяснение

Основная программа

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

Основная программа использует вспомогательную функцию для перечисления всех возможных способов получения значения посредством умножения, затем пытается создать значение путем сложения и возвращает кратчайшую возможность. Он также обрабатывает базовый случай (ввод1 ).

Вспомогательная функция

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

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


источник
0

GNU Prolog, 96 байт

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

Первая строка - это грамматика, которая реализует оценку недогрузки и работает в обратном направлении (на самом деле, она не совсем работает в прямом направлении из-за A#<B ограничения; измените ее A#<Nна более медленную программу, которая работает в обоих направлениях). Вторая строка определяет функциональный предикатs (который является функцией, которая реализована как решение этой программы), которая находит кратчайшую возможную строку, которая оценивается как число, указанное в качестве входных данных (это разочаровывающе многословно для относительно простой задачи, но это пролог для тебя…).

Программа должна быть достаточно понятной, учитывая, что это более или менее прямой перевод спецификации в грамматику, а затем в синтаксис Prolog; определение vговорит, что Nэто 1 в пустой строке, или Nэто A× BAменьше, чем Bменьше N), и строка является конкатенацией v(A)и v(B), или Nэто M+ 1, и строка :конкатенируется с v(M)конкатенацией со средством «S имеет некоторую длину» , но указание этого в качестве первой вещи в строке действует как подсказка для реализации Пролога, что она должна сначала проверить самую короткую длину (что означает, что мы получим самую короткую возможную длину для возвращаемого значения).* . Вторая строка немного тоньше;length(S,_)


источник