Найкоротша мережа доповнення


23

Ланцюг додавання - це послідовність цілих чисел, що починається з 1, де кожне ціле число, окрім початкового 1, є сумою двох попередніх цілих чисел.

Наприклад, ось ланцюжок додавання:

[1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Ось такі суми, які складають ланцюжок додавання:

1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
3 + 4 = 7
1 + 7 = 8
8 + 8 = 16
16 + 16 = 32
7 + 32 = 39
32 + 39 = 71

У цьому виклику вам буде дано додатне ціле число n, і ви повинні вивести одну з найкоротших ланцюжків додавання, яка закінчується n.

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

1: [1]
2: [1, 2]
3: [1, 2, 3]
4: [1, 2, 4]
5: [1, 2, 3, 5]
6: [1, 2, 3, 6]
7: [1, 2, 3, 4, 7]
11: [1, 2, 3, 4, 7, 11]
15: [1, 2, 3, 5, 10, 15]
19: [1, 2, 3, 4, 8, 11, 19]
29: [1, 2, 3, 4, 7, 11, 18, 29]
47: [1, 2, 3, 4, 7, 10, 20, 27, 47]
71: [1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Стандартні правила вводу / виводу тощо. Стандартні лазівки заборонені. Код гольфу: виграє найменше байтів.




1
Чи дозволяється нам виводити ланцюг у зворотному порядку?
Арнольд

@Arnauld Ні, це конкретне замовлення.
isaacg

Відповіді:


6

Haskell , 57 байт

c=[1]:[x++[a+b]|x<-c,a<-x,b<-x]
f n=[x|x<-c,last x==n]!!0

Жорстоке рішення. Спробуйте в Інтернеті!

Пояснення

Нескінченний список cмістить усі ланцюги додавання, упорядковані по довжині. Він визначається індуктивно з точки зору самого себе, шляхом взяття списку xз cі двох елементів з x, та додавання їх суми до x. Функція fзнаходить перший список у cтому, що закінчується потрібним числом.

c=            -- c is the list of lists
 [1]:         -- containing [1] and
 [x           -- each list x
  ++[a+b]     -- extended with a+b
 |x<-c,       -- where x is drawn from c,
  a<-x,       -- a is drawn from x and
  b<-x]       -- b is drawn from x.
f n=          -- f on input n is:
 [x           -- take list of those lists x
 |x<-c,       -- where x is drawn from c and
  last x==n]  -- x ends with n,
 !!0          -- return its first element.

4

Брахілог , 14 байт

∧≜;1{j⊇Ċ+}ᵃ⁽?∋

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

Представлення грубої сили, яке будує всі можливі ланцюги додавання, використовуючи ітеративне поглиблення, зупиняючись, коли знайдена ланцюг, що містить правильний аргумент. На відміну від більшості подань Брахілогів, це подання функції, яке вводить через свій правий аргумент (умовно називається вихідний) і виводить через його лівий аргумент (умовно називається Input); робити це дещо суперечливо, але метавідповідь з найвищою оцінкою на цю тему говорить, що це законно (і це відповідає нашим нормальним за замовчуванням функцій вводу / виводу для функцій). Якби ми використовували вхід і вихід більш звичайним способом, це було б 16 байт (∧≜;1{j⊇Ċ+}ᵃ⁽.∋?∧), оскільки права частина програми не змогла б скористатися неявним обмеженням (таким чином, знадобиться цей відключений та надано нове явне обмеження вартістю 2 байти).

Пояснення

∧≜;1{j⊇Ċ+}ᵃ⁽?∋
∧               Disable implicit constraint to read the left argument
 ≜;        ⁽    Evaluation order hint: minimize number of iterations
    {    }ᵃ     Repeatedly run the following:
   1      ᵃ       From {1 on the first iteration, results seen so far otherwise}
     j            Make {two} copies of each list element
      ⊇           Find a subset of the elements
       Ċ          which has size 2
        +         and which sums to {the new result for the next iteration}
             ∋    If the list of results seen so far contains {the right argument}
            ?     Output it via the left argument {then terminate}

Цікавою тонкістю є те, що відбувається під час першої ітерації, де вхід - це число, а не список, як на інших ітераціях; ми починаємо з числа 1, робимо по дві копії кожної цифри (робимо число 11), потім знаходимо її двозначне підряд (також число 11). Потім беремо його цифру, яка дорівнює 2, і як така послідовність починається так, [1,2]як ми хочемо. На ітерацій в майбутньому, ми починаємо зі списком , як [1,2], подвоюючи його [1,2,1,2], а потім взяти два-елемента підпослідовності ( [1,1], [1,2], [2,1]або [2,2]); Очевидно, що суми кожного з них будуть дійсними наступними елементами ланцюга додавання.

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


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

1
@Fatalize: це одна з тих вбудованих файлів, яка рідко з'являється, але коли вона вам потрібна, вона вам дійсно потрібна, оскільки немає віддаленого способу реалізувати її за допомогою інших структур управління. Як тільки я зрозумів, що це був виклик, решта прийшла досить прямо звідти.

2

Желе , 17 байт

’ŒP;€µ+þ;1Fḟ@µÐḟḢ

Виводить лексикографічно перше рішення за експоненціальним часом.

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

Як це працює

’ŒP;€µ+þ;1Fḟ@µÐḟḢ  Main link. Argument: n (integer)

’                  Decrement; n-1.
 ŒP                Powerset; generate all subarrays of [1, ..., n-1], sorted first
                   by length, then lexicographically.
   ;€              Append n to all generate subarrays.
     µ       µÐḟ   Filterfalse; keep only subarrays for which the chain between the
                   two chain separators (µ) returns a falsy value.
     µ             Monadic chain. Argument: A (array of integers)
      +þ               Add table; compute the sums of all pairs of elements in x,
                       grouping the results by the right addend.
        ;1             Append 1 to the resulting 2D array.
          F            Flatten the result.
           ḟ@          Filterfalse swapped; remove all elements of A that appear in
                       the result. This yields an empty list for addition chains.
                Ḣ  Head; select the first result.

2

JavaScript (ES6), 83 86 байт

Редагувати: виправлено для виведення списку у зворотному порядку

n=>(g=(s,a=[1])=>s-n?s>n||a.map(v=>g(v+=s,a.concat(v))):r=1/r|r[a.length]?a:r)(r=1)&&r

Демо


2

PHP, 195 байт

function p($a){global$argn,$r;if(!$r||$a<$r)if(end($a)==$argn)$r=$a;else foreach($a as$x)foreach($a as$y)in_array($w=$x+$y,$a)||$w>$argn||$w<=max($a)?:p(array_merge($a,[$w]));}p([1]);print_r($r);

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


На жаль, цей алгоритм не дає оптимальних відповідей, наприклад, для 15.
Ніл

@Neil зараз довше, але це працює. Я не маю ідеї в даний момент, як вирішити, який із обох способів є правильним. Можливо, грає прайм грає роль
Йорг Гюльсерманн

цей код не проходить тест 149. Довжина повинна бути 10, а не 11
J42161217

@Jenny_mathy Виправлено
Йорг Гюльсерманн

1

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

t={};s={1};(Do[While[Last@s!=#,s={1};While[Last@s<#,AppendTo[s,RandomChoice@s+Last@s]]];t~AppendTo~s;s={1},10^4];First@SortBy[t,Length@#&])&

.

створює інший найкоротший ланцюжок додавання кожного разу, коли ви запускаєте його

Спробуйте в Інтернеті
вставити код за допомогою ctrl + v, введіть введення, тобто [71] в кінці коду, і натисніть shift + enter


Оскільки я не маю доступу до Mathematica, яку довжину ланцюга це дає для введення 15?
Ніл

правильний {1, 2, 3, 5, 10, 15}
J42161217

3
Для введення 149 я отримав ланцюжок довжиною 11 від вашої програми, але існує одна довжиною 10 ( [1,2,4,5,9,18,36,72,77,149]). Здається, що ваша програма використовує випадкову вибірку, і не гарантується знайти оптимальне рішення.
Згарб

виправлено! але це займає більше часу
J42161217

1

Pyth, 13 байт

h-DsM^N2/#QyS

Тестовий набір

Дає лексикографічно перший найкоротший ланцюг. Це досить повільно, але не так вже й погано - 19завершується приблизно за 30 секунд за допомогою pypy.

Деякі ідеї рішення @ Dennis.

Мені дуже подобається цей - тут є багато тонких хитрощів.

Пояснення:

h-DsM^N2/#QyS
h-DsM^N2/#QySQ    Implicit variable introduction
            SQ    Inclusive range, 1 to input.
           y      Subsets - all subsets of the input, sorted by length then lexicographically
                  Only sorted subsets will be generated.
                  Our addition chain will be one of these.
        /#Q       Filter for presence of the input.
  D               Order by
 -                What's left after we remove
     ^N2          All pairs of numbers in the input
   sM             Summed
h                 Output the list that got sorted to the front.

Це все ще трохи важко зрозуміти, але дозвольте спробувати пояснити трохи детальніше.

Почнемо з того ySQ, що дає всі можливі впорядковані підмножини [1, 2, ... Q], збільшуючи порядок розміру. Найкоротший ланцюг додавання, безумовно, один із них, але нам потрібно його знайти.

Перше, що ми зробимо - це відфільтрувати список, щоб зберегти лише списки, які містять Q. Ми робимо це за допомогою /#Q.

Далі ми упорядковуємо список тим, що залишилося після того, як вилучимо результат певної функції. -Dзамовлення залишком, після чого щось видалили.

Ми видаляємо те sM^N2, звідки Nє список , з якого вилучаємо речі. ^N2дає декартовий продукт Nіз самим собою, всі можливі пари двох елементів у N.sMпотім підсумовує кожну з пар.

Який найменший можливий результат після того, як ми зробимо це видалення? Ну, і найменший елемент у списку вводу, безумовно, залишиться, тому що всі числа позитивні, тому будь-яка сума двох чисел буде більшою за найменше число. І буде хоча б одне число, тому що ми перевірили, чи вхід присутній у списку. Тому найменший можливий результат буде тоді, коли кожне число, крім найменшого числа, є сумою двох інших чисел у списку, а найменше число у списку - 1. У цьому випадку ключ сортування буде[1] . Ці вимоги означають, що список повинен бути ланцюжком додавання.

Отже, ми сортуємо додаткові ланцюги до переду. Пам'ятайте, що він yнадає підмножини в порядку збільшення розміру, тому список, відсортований на фронт, повинен бути однією з найкоротших ланцюжків додавання. hВибирає цей список.

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