Самородки кода


18

Самородки кода

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

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

Размеры упаковок куриных самородков повсюду, и в зависимости от того, где вы живете, стандартные размеры тоже меняются. Однако в ближайшем [месте, где обслуживаются самородки], имеются следующие размеры пакетов самородков:

4, 6, 9, 10, 20, 40

Теперь вы можете заметить, что вы не можете заказать определенные комбинации самородков. Например, 11самородки невозможны, так как не существует комбинации, которая в 11точности равна . Тем не менее, вы можете сделать 43, получив 1 пачку 20, 1 пачку 10, 1 пачку 9и 1 пачку 4,

20 + 10 + 9 + 4 = 43 (597)

где 597каждый член возводится в квадрат и складывается вместе (подсказка: оптимальное решение имеет это как наибольшее значение) . Конечно, есть и другие способы изготовления 43, но, как вы знаете, чем больше самородков в упаковке, тем дешевле они становятся за самородок. Таким образом, вы хотите в идеале купить наименьшее количество упаковок и в больших количествах, чтобы минимизировать ваши затраты.

Задание

Вы должны создать программу или функцию, которая принимает список целых чисел, соответствующих требованиям каждого человека. Затем вы должны рассчитать и распечатать наиболее экономичный α- заказ на покупку куриных наггетсов. Наиболее экономически выгодным α- порядком является комбинация, при которой сумма квадратов каждого количества является наибольшей. Если нет абсолютно никакого способа , чтобы купить самородки отлично, вы должны напечатать на falsy значение , например 0, False, Impossible!или все , что доступно на вашем языке.

Пример ввода / вывода:

[2 7 12 4 15 3] => [20 10 9 4]
     1, 1, 2, 1 => False
  6 5 5 5 5 5 9 => 40
      [6, 4, 9] => 9 10
              1 => 0
            199 => 40, 40, 40, 40, 20, 10, 9
              2 => Impossible!

Вот список идеальных решений для первых 400. Обратите внимание, что они не отформатированы так, как я ожидал, ваши будут tupleв форме (N lots of M).

правила

  1. Нет стандартных лазеек.
  2. Не использовать встроенные функции, которые выполняют все или большую часть задачи, например, FrobeniusSolveв Mathematica.

α - Чтобы прояснить это на примере, вы также могли бы сделать 43, выполнив 4 + 6 + 6 + 9 + 9 + 9 = 43 (319), но это не было бы оптимальным, и, следовательно, неправильный вывод, так как сумма квадратов меньше, чем комбинация, которую я отметил во введении. По сути, более высокая сумма квадратов = более низкая стоимость = наиболее экономически эффективны.


Есть ли ограничения по времени / памяти?
Деннис

@ Денис Нет ограничений по времени и памяти.
Каде

4
Это на самом деле четверг.
mbomb007

4
@ mbomb007 Проницательное наблюдение: P Я поправил вступление.
Каде

2
Мне нужно как-то использовать теорему о курице МакНуггет ...
Stretch Maniac

Ответы:


7

Pyth, 26 25 байт

e+Zo.aNf!-TCM"  
("./sQ

Обратите внимание, что есть некоторые непечатаемые символы. Попробуйте онлайн: Демонстрация . Это довольно медленно (но не так медленно, как мое 26-байтовое решение).

Объяснение:

                          implicit: Q = input list
                     sQ   sum(Q)
                   ./     generate all integer partitions
       f                  filter for partitions T, which satisfy:
             "   ("          string containing chars with the ASCII-values of 4,6,9,10,20,40
           CM                convert each char to the ASCII-value
         -T                  remove this numbers from T
        !                    and check, if the resulting list is empty
    o                      order the remaining subsets N by:
     .aN                      the vector length of N (sqrt of sum of squares)
  +Z                       insert 0 at the beginning
 e                         print the last element

Pyth, 32 байта

e+Zo.aNfqsTsQysm*]d/sQdCM"  
(

Обратите внимание, что есть некоторые непечатаемые символы. Попробуйте онлайн: Демонстрация Эта версия намного быстрее. Он находит решение для ввода [6,7,8]примерно за одну секунду, а решение для ввода - [30]примерно за 90 секунд.

Объяснение:

                                 implicit: Q = input list
                          "...(  the string containing chars with the ASCII-values of 4,6,9,10,20,40
                        CM       convert each char to the ASCII-value
                m                map each number d to:
                  ]d                create the list [d]
                 *  /sQd            and repeat it sum(Q)/d times
               s                 unfold
              y                  generate all subsets
        f                        filter for subsets T, which satisfy:
         qsTsQ                      sum(Q) == sum(T)
    o                            order the remaining subsets N by:
     .aN                            the vector length of N (sqrt of sum of squares)
  +Z                             insert 0 at the beginning
 e                               print the last element

Почему это по площади суммы квадратов, а не просто сумма?
mbomb007

1
@ mbomb007 Потому что это не важно. Если a> b, то sqrt (a)> sqrt (b) и наоборот. И использование .aметода короче, чем возведение в квадрат и суммирование s^R2.
Якуб

5

Perl 175 153

sub f{my$n=$_[0];if(!$n){return 1;}foreach$o(40,20,9,10,6,4){if($n>=$o&&f($n-$o)){print"$o ";return 1;}}return 0;}$n+=$_ for@ARGV;if(!f($n)){print":(";}

Принимает входные данные из аргументов программы. Печатает :(, если не может найти идеальное решение.

Код Ungolfed:

sub f
{
    my $n = $_[0];
    if(!$n)
    {
        return 1;
    }
    foreach $o(40,20,9,10,6,4)
    {
        if($n>=$o&&f($n-$o))
        {
            print "$o ";
            return 1;
        }
    }
    return 0;
}

$n += $_ for @ARGV;
if(!f($n))
{
    print ":(";
}

PS: Это, вероятно, первая запись, которая не займет 10 минут 1 2;)

Проверьте это здесь.


Поздравляю с тем, что пока является самой быстрой программой! Это также может быть быстрее, чем моя справочная программа: P Я добавил идеальную ссылку внизу вашего поста, чтобы люди могли видеть результат.
Каде

Ваш код может выдавать неправильный вывод. Ввод 18должен печатать 9 9, а не 4 4 10.
Деннис

Есть и другие неверные выводы. Если я не ошибаюсь, вы можете исправить все их, поменяв местами порядок 9и 10.
Деннис

@ Деннис Спасибо, исправил это!
Томас Олтманн

3

CJam, 45 29 28 байт

q~:+_[40K9A6Z)U]m*_::+@#=0-p

Обратите внимание, что этот подход очень медленный и требует много памяти.

Попробуйте онлайн в интерпретаторе CJam .

Это может быть значительно ускорено за счет 5 байтов:

q~:+_40/4+[40K9A6Z)U]m*_::+@#=0-p

Сложность по-прежнему экспоненциальна в сумме входных данных, но она должна обрабатывать контрольные примеры до 159 с онлайн-интерпретатором и до 199 с Java-интерпретатором за пару секунд.

Попробуйте онлайн в интерпретаторе CJam .

идея

Оптимальная покупка (максимальная сумма квадратов) является допустимой покупкой (правильное количество самородков) , который имеет столько , сколько 40 - х года , как это возможно, тогда как многие 20 'S , насколько это возможно, тогда как многие 9 «S , насколько это возможно (например, 9 9в предпочтительно более 10 4 4) и т. д. в течение 10 , 6 и 4 лет .

При таком подходе мы генерируем декартово произведение N копий массива [40 20 9 10 6 4 0] , где N - желаемое количество слепков. N - это (плохая) верхняя граница количества покупок, которые мы должны сделать. В ускоренной версии кода мы используем N / 40 + 4 .

Из-за того, как упорядочен массив, декартово произведение будет начинаться с вектора [40 ... 40] и заканчиваться вектором [0 ... 0] . Мы вычисляем индекс первого вектора, который имеет правильную сумму (которая также будет иметь оптимальную сумму квадратов), извлекаем соответствующий элемент массива, удаляем нули, которые служили заполнителями, и выводим результат.

Если вектор не может быть найден, индекс будет равен -1 , поэтому мы получаем [0 ... 0] , который вместо этого выведет пустой массив.

Код

q~                            e# Read from STDIN and evaluate the input.
  :+                          e# Push N, the sum of all elements of the resulting array.
     [40K9A6Z)U]              e# Push B := [40 20 9 10 6 4 0].
    _           m*            e# Push B**N, the array of all vectors of dimension N
                              e# and coordinates in B.
                  _::+        e# Copy and replace each vector by its sum.
                      @#      e# Get the first index of N.
                        =     e# Retrieve the corresponding element.
                         0-p  e# Remove 0's and print.

Это может быть одна из немногих ситуаций, когда отработка решения вручную будет быстрее, чем доведение кода до конца ... хорошая работа независимо от :)
Kade

2

Юлия, 126 байт

r->(t=filter(i->all(j->j[4,6,9,10,20,40],i),partitions(sum(r)));show(!isempty(t)&&collect(t)[indmax(map(k->sum(k.^2),t))]))

Это создает безымянную функцию, которая принимает массив в качестве входных данных и печатает массив или логическое значение в STDOUT, в зависимости от того, существует ли решение. Чтобы назвать его, дайте ему имя, например f=n->....

Ungolfed + объяснение:

function f(r)
    # Nugget pack sizes
    packs = [4, 6, 9, 10, 20, 40]

    # Filter the set of arrays which sum to the required number of nuggets
    # to those for which each element is a nugget pack
    t = filter(i -> all(j -> jpacks, i), partitions(sum(r)))

    # Print the boolean false if t is empty, otherwise print the array of
    # necessary nugget packs for which the sum of squares is maximal
    show(!isempty(t) && collect(t)[indmax(map(k -> sum(k.^2), t))])
end

Примеры:

julia> f([1])
false

julia> f([2,7,12,4,15,3])
[20,10,9,4]

1

Python 3 - 265 символов

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,9):
 for j in range(6*f):
  for x in i.combinations((4,6,9,10,20,40,)*f,j+1):
   if sum(n)==sum(x):m.append(x)
if m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Показывать интервал:

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,5):
 for j in range(6*f):
\tfor x in i.combinations((4,6,9,10,20,40,)*f,j+1):
\t if sum(n)==sum(x):m.append(x)
\t\tif m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Проходит все тесты

Примечание: я не знаю, пройдет ли это все случаи, потому что это так медленно ... Но это должно ...


Ничто не выглядит неправильно с этим прямо сейчас, я проверю это и посмотрю. Как только я вернусь домой, я добавлю эталонную программу, которую не использовали, чтобы создать список в Gist. Хотя у меня не было времени, я считаю, что для всех случаев это заняло где-то 8-12 минут.
Каде

@ Vioz- Отлично! : D
Бета-распад

Похоже, что я могу ошибаться, после тестирования 36 он проходит около 40 миллионов комбинаций (точнее 40 007 602) перед запуском в MemoryError. Это может быть ограничением моей рабочей машины, поскольку она имеет только 4 ГБ памяти.
Каде

@ Vioz- Хм ... Ну, я безнадежно продолжаю тестирование на своем телефоне ...
Бета-распад

1
@undergroundmonorail Если вы используете его только один раз, то для <= 4 символов прямой импорт лучше (5 безубыточных). Но если вы используете его более одного раза, то from blah import*всегда лучше. Единственное исключение, о котором я могу подумать, это если у вас есть несколько imports, и это единственное время, которое приходит на ум, когда asэто действительно полезно.
Sp3000

1

JavaScript, 261 256 261

d="length";function g(a){for(z=y=0;y<a[d];z+=+a[y++]);return z}x=[40,20,10,9,6,4];l=prompt().split(",");o=g(l);p=[];for(i=0;i<x[d];i++)r=g(p),s=r+x[i],(s<o-3||s==o)&&p.push(x[i]),(i==x[d]-1||40<o-r)&&r+x[i]<o-3&&(i=-1,0==i||o-r<p[p[d]-1]&&p.pop());g(p)==o&&p||0

Я не уверен, что все в порядке, это похоже на работу, но я наверняка скучаю по вещам.

Это , кажется, не быть медленным , хотя, до 123456он выводит [40 x 3086, 10, 6]почти немедленно.

Объяснение:

Перебор по размерам самородков (самый большой сначала)

  • Если сумма стека плюс размер самородка меньше цели - 3 -> поместите его в стек
  • Если осталось более 40 -> сбросить счетчик цикла
  • Если сумма стека больше цели, когда был достигнут последний размер самородка -> вытолкнуть последний элемент, сбросить счетчик цикла
  • Если сумма стека складывается, вернуть ее, в противном случае вернуть 0

За 199 | 1 построенный стек выглядит так

i | stack
0   [40]
0   [40, 40]
0   [40, 40, 40]
0   [40, 40, 40, 40]
0   [40, 40, 40, 40]
1   [40, 40, 40, 40, 20]
2   [40, 40, 40, 40, 20, 10]
3   [40, 40, 40, 40, 20, 10, 9]
4   [40, 40, 40, 40, 20, 10, 9]
5   [40, 40, 40, 40, 20, 10, 9]
==> [40, 40, 40, 40, 20, 10, 9]

За 1

i | stack
0   []
1   []
2   []
3   []
4   []
5   []
==> 0

1
Ваш подход, кажется, не проверяет, может ли быть достигнута цель. 11печатает [6]и 18печатает [10, 4].
Деннис

@ Денис Привет, спасибо за указание на это. Это было поздно ночью вчера. Исправлено это за 5 символов. 18 напечатано, [10,4]потому что мне не хватало пары паренов. Проверка была действительно неправильной, я просто проверил, был ли хотя бы один элемент в наборе результатов, а не правильно ли он суммируется. Я не знаю, что я там думал
C5H8NNaO4
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.