Вісім монет для чесного короля


22

Це "аналог" чергової головоломки, Вісім монет для чесного короля на Puzzling.SE.

Ви можете прочитати вищезазначений пазл для фону. Деталі про цю головоломку наступні.

Створюється набір з 8 видів монет різної вартості, король хоче, щоб ви дізналися максимальний N такий, що будь-яку кількість ціни від 0 до N можна оплатити комбінацією не більше 8 монет і без зборів.

Наприклад, (взято з відповіді Глорфінделя). Якщо набір монет значеннями 1, 2, 5, 13, 34, 89, 233, 610, ваша програма повинна вивести 1596, оскільки кожне число між 0 і 1596 (включно) може бути представлене сумою не більше ніж 8 чисел із даного списку (номери можуть повторюватися), тоді як 1597 не можна представити таким чином.

Математично, якщо вхід - це множина S, що складається з 8 натуральних чисел, бажаний вихід N задовольняє, що для будь-якого числа n між 0 і N існує x1, x2, x3, ..., x8, таких що

x1+x2+...+x8=ніх1,х2,...,х8{0}S

Ваша мета - написати програму, функцію або фрагмент, який приймає 8 цифр як вхід, і виводить максимальний N, як описано вище.

Правила:

  • Дозволено гнучко введення / виведення, тому програма може приймати дані в будь-якій формі, яка найкраще підходить. Ви можете припустити, що вхідні номери відсортовані так, як найкраще підходить вашій програмі.
    • Будь ласка, вкажіть це у своїй відповіді, якщо ваша програма залежить від порядку введення
  • Введення - це набір з 8 різних натуральних чисел (без нулів). Вихід - одне невід'ємне ціле число.
    • Якщо у наборі введення немає 1, ваша програма повинна вивести 0, оскільки будь-яке число від 0 до 0 задовольняє вимозі.
    • У випадку невірного введення (набір містить нульові, негативні або повторювані числа), ваша програма може робити все, що завгодно.
  • Стандартні лазівки заборонені.
  • Ваша програма повинна працювати протягом декількох хвилин на сучасному комп’ютері.

Тестові приклади (в основному взяті з відповідей під пов’язаним запитанням про Загадка):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

Це , тому виграє найкоротша програма або фрагмент кожної мови!


1
Гарна головоломка, але я особисто думаю, що ще кілька тестових випадків були б корисні для перевірки наших матеріалів.
Містер Xcoder

Чи не було б краще зробити параметр розміру вводу? Підходи грубої сили боротимуться з 8
Луїс Мендо

1
@iBug Тоді звичайне правило - це на кшталт "подання повинно працювати протягом хвилини на сучасному комп'ютері". Це нечітко, але, як правило, досить добре, тому що різниця між грубою силою та ефективними підходами дуже велика
Луїс Мендо

1
Груба сила все ще можлива, якщо ваш часовий ліміт "кілька хвилин". Трохи модифікована версія моєї відповіді запускає останній тестовий випадок через 1м20 на моєму 7-річному ноутбуці.
німі

1
@Arnauld Уточнено
iBug

Відповіді:



9

Желе , 12 байт

œċⱮ8Ẏ§ṢQJƑƤS

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

В середньому займає ~ 3,7 секунди для запуску всіх тестових випадків на TIO на моєму телефоні, тому дивно, що це досить швидко.

Пояснення

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell, 56 50 байт

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

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

Підхід грубої сили. Додайте 0до списку монет і спробуйте всі комбінації 8 вибірок. Знайдіть перше число, nяке не дорівнює сумі жодного з вибору, і поверніть n-1.

Займає близько 5 м30 для [1, 2, 5, 13, 34, 89, 233, 610]мого 7-річного обладнання для ноутбука.

Редагувати: -6 байт завдяки @ Ørjan Johansen

Ще коротша версія (-2 байти, знову ж таки завдяки @ Ørjan Johansen) є

Haskell, 48 байт

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

але він використовує значно більше пам’яті і стикається з великою пейджингом на моїй машині і не закінчується «протягом декількох хвилин».


1
Можна використовувати mapM(0:)$c<$c. (Насправді mapM(:0:c)cслід попрацювати, але вичерпайте час на TIO для даного тестового випадку.)
Ørjan Johansen

4

Желе , 9 байт

Żœċ8§ḟ’$Ṃ

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

Як це працює

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃекономить один байт, але я не впевнений, що 8,5 хвилин вважається кількома .
Денніс


4

JavaScript (ES6),  100 88 80  76 байт

Це по суті пошук грубої сили, але посилений обрізкою, щоб пришвидшити його. Середній час виконання тестових випадків близький до 1 секунди на TIO.

Передбачається, що вхідний масив відсортований від найвищого до нижнього.

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

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

Прокоментував

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Парі / GP , 57 байт

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

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


це за допомогою функції генерації?
нехай яскравий

1
@donbright Так.
алефальфа

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

2

Python 2 , 125 115 111 байт

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

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

Очікує список цілих чисел як вхід.

Пояснення:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6, 65 63 41 байт ( 39 37 символів)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

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

Це анонімний блок, який передає свої дані у вигляді масиву. Це (0,|@_)швидкий спосіб додати 0до @_, і, хоча це робиться двічі, він все ще трохи коротший, ніж @_.push: 0;тоді знадобиться пробіл після _. Це підхід грубої сили, який трохи сирить за тим, що це 8 комбінацій. Після перехресного додавання створюється анонімний список для послідовних значень. З математичними операторами списки оцінюють їх довжину, тому -1 тягне подвійний збір: облік 0 і примушування до Int.

Це може зайняти солодкий час, але змінивши один або обидва (0,|@_)до (0,|@_.unique)першого, forце може бути значно скорочено. Це додає +7 (час виконання <60s) або +14 (час виконання <10s), якщо ви вважаєте, що перший занадто повільний (я зробив це для зв'язаного коду, щоб уникнути тайм-аутів через 60 секунд).

Редагувати: JoKing в коментарях покращив його (та сама ідея, перекреслити додавання, а потім повернути останній результат поспіль) до дивовижних 39 символів (41 байт):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

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

Для остаточної таблиці не потрібно 0, зберігаючи кілька байтів, потрібно лише один раз додати 0. У xx 3наслідує для циклу ( до сих пір сирів на монетах , що є ступенем 2). Підрозділ firstповертає перше число у нескінченному списку 0..*( ^Infтеж можливо, але не економить місце), +1який не є членом перехресного списку. Як і у мене, це повільно, тому додайте +7 за uniqueпершим рівним, якщо вам здається, що це занадто повільно для вказівки.


1
48 байт . Технічно uniqueце не потрібно, але це дуже прискорює його
Джо Кінг

@JoKing приємно, я не знаю, чому я не думав про використання xx. Я знав, що повинен бути спосіб зробити остаточну таблицю набагато коротше, використовуючи задані функції, але мій мозок не працював.
user0721090601

Це xx 1повинно бутиxx 3
Jo King

@JoKing виправлено. Також я зрозумів, що два символи (але жодних байтів) можна зберегти, використовуючи^∞
user0721090601

Насправді ви можете зберегти кілька байтів, (1...*∉@_)-1а не використовувати first(що я розумію, це той самий метод, який я тут використовував )
Jo King

1

JavaScript (Node.js) , 171 145 115 байт

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

Спробуйте в Інтернеті! Порт @ Маркова відповідь Python 3. 108 байт у Firefox 30-57:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))

1

Мова Вольфрама (Mathematica) , 46 байт

0//.x_/;Min[Tr/@FrobeniusSolve[#,x+1]]<9:>x+1&

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

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


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