Найкоротше представлення номера Underload


13

Текст аромату

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

Щоб зробити це просто, ми розглянемо лише наступний підмножина команд Underload:

  • : - Ця команда дублює верхній елемент у стеку.
  • * - Ця команда об'єднує два найпопулярніші елементи стека в один елемент.

Ми визначаємо цифру Underload N як рядок :і, *що при виконанні, споживає верхній елемент у стеку, і створюємо N примірників цього елемента, з'єднаних разом. Деякі приклади:

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

Загалом, ви побачите, що якщо Mі Nє цифри Underload M і N, то :N*це число N + 1, і MNце число M × N.

Змагання

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

Зразки входів і виходів: ("Введення - 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).

Якщо вхід не є натуральним натуральним числом, ви можете повернути помилку, викликати невизначене поведінку або навіть не вдатися до припинення. Оцінено пояснення методу Вашого подання для пошуку відповіді.

Застосовуються стандартні обмеження лазівки: жоден додатковий ввід, ніякі веб-запити, значення виводу / повернення не повинні бути точно відповіддю, а не нескінченним випадковим потоком :і *т.д.


@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/'*:'=}%

Дякую Говарду, з рішення якого я вкрав пару однозначних налаштувань.


Ха-ха, на введення 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>виходить []без помилок.
Говард

@Howard, ах, golfscript.apphb.com повинен мати стару версію. Але виявляється, що я помилявся, тому що ця заміна призводить до отримання неправильного виводу для введення '1'.
Пітер Тейлор

Яке ви можете виправити ((=замість -1=.
Говард

І golfscript.apphb.com дійсно виконує стару версію, приклад вкладених циклів не працює.
Говард

4

Пітон 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. ... і ... або ... заміна на ... якщо ... інше ... не працює, оскільки "" оцінюється як хибне. хв рядків дає одну з найкоротших рядків. Python 2.7 зберігає 1 символ, використовуючи / замість //.

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

Тестові приклади:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'

1
" min рядків дає одну з найкоротших рядків " не відповідає дійсності, якщо ви не надаєте необов'язковий аргумент key=len. Це дає лексикографічно найдавніший рядок. ( Приклад ). Оскільки '*' < ':'це означає, що у вас є упередженість щодо рішень, що передбачають повноваження 2, але вони завжди найкоротші?
Пітер Тейлор

1
Відповідь: насправді упередження є складнішим, але це не завжди дає правильну відповідь. Найменший контрприклад u(33), для якого сортування лексикографічно дає 14-ти лінійку, ::**::*::*:***а сортування за довжиною дає 12-знакову::*:*:*:*:**
Пітер Тейлор

1
Я ніколи не знав цього про порівняння струн Python. Я оновив свою відповідь.
isaacg

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

Брахілог 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 + (подання, отримане з рекурсивної дзвінок). Це гарантовано для пошуку всіх можливих уявлень про завантаження числа (ми можемо застосувати етап множення "двічі поспіль", множивши разом більше 2 чисел, і етап збільшення два рази поспіль, розділяючи їх на етап множення, який помножується разом лише одне число). Нам не потрібен явний базовий випадок, оскільки розкладання 1 на прості множники дає нам порожній список, і таким чином ми будуємо його на етапі множення, який множує нульові числа разом.

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


0

J - 81 char

Для нащадків це було найкраще, що я міг зробити в Дж.

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

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

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

Потім ми додаємо до цього списку запис для попереднього результату, укрепленого за допомогою :та *, і сортуємо цей список за довжиною ( (/:#&>)). Нарешті, ми беремо перший результат із цього списку ( 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

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,[]).

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

Програма повинна бути досить зрозумілою, враховуючи, що це більш-менш прямий переклад специфікації на граматику, а потім у синтаксис Prolog; визначення vговорить , що Nце один в порожній рядку, або Nце A× BAменш ніж Bменше N) і рядок є конкатенація v(A)і v(B), або Nє M+ 1 і рядок :об'єднується з v(M)зчіплюються з *. Другий рядок трохи тонкіший;length(S,_) означає "S має деяку довжину", але вказуючи це як перше, що в рядку, виступає натяком на реалізацію Prolog, що він повинен спочатку перевірити найкоротші довжини (це означає, що ми отримаємо найкоротшу можливу довжину для повернення значення) .

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