Восемь монет для прекрасного короля


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=nandx1,x2,...,x8{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 Clarified
iBug

Ответы:


14

Python 3 , 113 62 байта

for i in[1]*3:x|={a+b for a in x for b in x}
while{i+1}&x:i+=1

Вот xвходные данные в виде набора целых чисел и iвыходные данные.

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

(Спасибо: Эрик Outgolfer, мистер Xcoder, Линн)



x=0,*xсохраняет 1 байт. Еще лучше, x+=0,сохраняет 2.
Мистер Xcoder

78 байт в Python 2.
Lynn

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 минут [1, 2, 5, 13, 34, 89, 233, 610]на моем 7-летнем ноутбуке.

Изменить: -6 байт благодаря @ Örjan Йохансен

Еще более короткая версия (-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 для данного теста.)
Орджан Йохансен

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

Пари / ГП , 57 байт

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

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


это с помощью производящей функции?
Дон Брайт

1
@donbright Да.
алефальфа

1
это потрясающе .. один из немногих ответов, не прибегая к грубому решению. во многих языках, вероятно, нет встроенных полиномиальных символических функций. Par 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 (время выполнения <60 с) или +14 (время выполнения <10 с) к счету, если вы чувствуете, что первый слишком медленный (я сделал это для связанного кода, чтобы избежать тайм-аутов через 60 секунд).

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

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

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

В итоговой таблице не требуется 0, сохраняя несколько байтов, просто добавляя 0 за один раз. В xx 3подражает для цикла ( до сих пор сыров на монетах , являющихся степенью 2). firstЮгу возвращает первое число в бесконечном списке 0..*( ^Infэто тоже возможно, но не экономии места) которого +1не является членом поперечному добавленного списка. Как и у меня, он медленный, поэтому добавьте +7 для uniqueпервого после первого, если вы чувствуете, что он слишком медленный для ориентиров.


1
48 байтов . Технически, uniqueэто не нужно, но это сильно его ускоряет
Джо Кинг,

@ Отлично, я не знаю, почему я не думал об использовании xx. Я знал, что должен быть способ сделать окончательное табулирование намного более коротким способом, используя функции набора, но мой мозг не работал.
user0721090601

xx 1Должно бытьxx 3
Джо Кинг

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

На самом деле, вы можете сохранить несколько байтов с (1...*∉@_)-1 вместо использования first(я понимаю, что это тот же метод, который я использовал здесь )
Джо Кинг,

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)))

Попробуйте онлайн! Порт @ Mark's 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

Wolfram Language (Mathematica) , 46 байтов

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

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

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.