Pepitas de código


18

Pepitas de código

É uma situação hipotética em que é sexta-feira à noite e você convidou os amigos habituais do golfe para participar do seu hobby favorito: o golfe com código. No entanto, como essa é uma tarefa que drena o cérebro, você precisa pegar um pouco de comida para o grupo para poder jogar o máximo possível de seu código.

Agora, o lanche favorito de todos é o nuggets de frango, mas há um problema: não há um pacote único que cubra as necessidades de todos. Portanto, como você já está no clima do golfe, decide criar um programa que descubra exatamente quais pacotes você deve comprar para poder atender às necessidades de todos os Nugget.

Os tamanhos das embalagens de pepitas de frango estão por todo o lado e, dependendo de onde você mora no mundo, os tamanhos padrão também mudam. No entanto, o [local que serve pepitas mais próximo ] armazena os seguintes tamanhos de pacotes de pepitas:

4, 6, 9, 10, 20, 40

Agora você pode perceber que não pode pedir certas combinações de pepitas. Por exemplo, 11pepitas não é possível, pois não existe uma combinação que seja 11exatamente igual . No entanto, você pode fazer 43obtendo 1 pacote de 20, 1 pacote de 10, 1 pacote de 9e 1 pacote de 4,

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

onde 597cada termo é elevado ao quadrado e somado (dica: a solução ideal tem isso como o valor mais alto) . É claro que existem outras maneiras de fazer 43, mas como você sabe, quanto mais pepitas por pacote, mais barato fica por pepita. Portanto, você deseja idealmente comprar o menor número de embalagens e as maiores quantidades para minimizar seu custo.

A tarefa

Você deve criar um programa ou função que faça uma lista de números inteiros correspondentes aos requisitos de cada pessoa. Você deve calcular e imprimir a ordem α mais econômica para comprar os nuggets de frango. A ordem α mais econômica é a combinação pela qual a soma dos quadrados de cada quantidade é a mais alta. Se não há absolutamente nenhuma maneira de comprar as pepitas perfeitamente, você deve imprimir um valor Falsas tais como 0, False, Impossible!, ou o que está disponível no seu idioma.

Exemplo de E / S:

[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!

Aqui está a lista de soluções ideais para os primeiros 400. Observe que eles não estão formatados como eu esperaria que o seu fosse, cada um tupleestá no formato (N lots of M).

Regras

  1. Sem brechas padrão.
  2. Não há uso de funções internas que executam toda ou a maioria das tarefas, como FrobeniusSolveno Mathematica.

α - Para esclarecer isso com um exemplo, você também pode fazer 43 fazendo 4 + 6 + 6 + 9 + 9 + 9 = 43 (319), mas isso não seria o ideal e, portanto, uma saída incorreta, pois a soma dos quadrados é menor que a combinação que observei na introdução. Essencialmente, maior soma de quadrados = menor custo = mais econômico.


Existem limites de tempo / memória?
Dennis

@ Dennis Não há tempo ou limites de memória.
Kade

4
Na verdade é quinta-feira.
mbomb007

4
@ mbomb007 Observação astuta: P Ajustei a introdução.
Kade

2
Eu preciso usar o frango McNugget teorema de alguma forma ...
estiramento Maniac

Respostas:


7

Pitão, 26 25 bytes

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

Observe que existem alguns caracteres não imprimíveis. Experimente online: Demonstração . É bastante lento (mas não tão lento quanto a minha solução de 26 bytes).

Explicação:

                          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

Pitão, 32 bytes

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

Observe que existem alguns caracteres não imprimíveis. Experimente online: Demonstração Esta versão é muito mais rápida. Ele encontra a solução para a entrada [6,7,8]em cerca de um segundo e a solução para a entrada [30]em cerca de 90 segundos.

Explicação:

                                 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

Por que é pelo quadrado da soma dos quadrados, e não apenas pela soma?
mbomb007

1
@ mbomb007 Porque isso não importa. Se a> b, então sqrt (a)> sqrt (b) e vice-versa. E o uso do .amétodo é mais curto que o quadrado e a soma s^R2.
Jakube

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":(";}

Pega a entrada dos argumentos do programa. Imprime um :( se não conseguir encontrar uma solução perfeita.

Código 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: Esta é provavelmente a primeira entrada que não leva 10 minutos para 1 2;)

Confira aqui.


Parabéns pelo que parece ser o programa mais rápido até agora! Também pode ser mais rápido do que o meu programa de referência: P Adicionei um link ideone na parte inferior da sua postagem para que as pessoas possam ver a saída.
Kade

Seu código pode produzir uma saída incorreta. A entrada 18deve ser impressa 9 9, não 4 4 10.
Dennis

Existem outras saídas incorretas também. Se não me engano, você pode consertar todos eles trocando a ordem de 9e 10.
Dennis

@ Dennis Obrigado, consertou!
Thomas Oltmann

3

CJam, 45 29 28 bytes

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

Observe que essa abordagem é muito lenta e consome muita memória.

Experimente on-line no intérprete CJam .

Pode ser acelerado significativamente ao custo de 5 bytes:

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

A complexidade ainda é exponencial na soma da entrada, mas isso deve lidar com casos de teste de até 159 com o interpretador online e até 199 com o interpretador Java em alguns segundos.

Experimente on-line no intérprete CJam .

Idéia

Uma compra óptima (soma máxima de quadrados) é uma compra válido (número correcto de pepitas) que tem o maior número 40 'é possível, então o maior número 20 ' é possível, então o maior número 9 é possível (por exemplo, 9 9é preferível 10 4 4) e assim por diante para 10 , 6 e 4 .

Nesta abordagem, geramos o produto cartesiano de N cópias da matriz [40 20 9 10 6 4 0] , em que N é o número desejado de pepitas. N é um limite superior (ruim) para o número de compras que temos que fazer. Na versão acelerada do código, usamos N / 40 + 4 .

Por causa de como a matriz é ordenada, o produto cartesiano começará com o vetor [40 ... 40] e terminará com o vetor [0 ... 0] . Calculamos o índice do primeiro vetor que possui a soma correta (que também terá a soma ideal de quadrados), recuperamos o elemento da matriz correspondente, removemos os zeros que serviram como espaços reservados e imprimimos o resultado.

Se nenhum vetor puder ser encontrado, o índice será -1 , então recuperamos [0 ... 0] , que imprimirá uma matriz vazia.

Código

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.

Esta pode ser uma das poucas situações em que trabalham a solução à mão seria mais rápido do que deixar o acabamento código .. bom trabalho independentemente :)
Kade

2

Julia, 126 bytes

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

Isso cria uma função sem nome que aceita uma matriz como entrada e imprime uma matriz ou booleano em STDOUT, dependendo da existência de uma solução. Para chamá-lo, dê um nome, por exemplo f=n->....

Ungolfed + explicação:

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

Exemplos:

julia> f([1])
false

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

1

Python 3 - 265 caracteres

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)

Mostrando espaçamento:

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)

Passa em todos os casos de teste

Nota: Não sei se isso passará em todos os casos porque é muito lento ... Mas deveria ...


Nada parece errado com isso agora, vou testá-lo e ver. Quando chegar em casa, adicionarei um programa de referência não destruído que usei para gerar a lista que está no Gist. Enquanto eu não estava no tempo, acredito que demorou algum tempo no intervalo de 8 a 12 minutos para todos os casos.
25415 Kade

@ Vioz- Brilhante! : D
Beta Decay

Parece que eu posso estar errado, depois de testar 36, ele passa por cerca de 40 milhões de combinações (40.007.602 para ser exato) antes de executar um MemoryError. Porém, isso pode ser uma limitação da minha máquina de trabalho, pois ela possui apenas 4 GB de memória.
Kade

@ Vioz- Hm ... Bem, é inútil para mim continuar testando no meu telefone ...
Decay Beta

1
@undergroundmonorail Se você o estiver usando apenas uma vez, para <= 4 caracteres uma importação direta é melhor (5 intervalos iguais). Mas se você estiver usando mais de uma vez, from blah import*é sempre melhor. A única exceção que posso pensar no que foi dito acima é se você tem vários imports, que é o único momento que vem à mente onde asé realmente útil.
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

Não tenho certeza se está tudo bem, parece funcionar, mas certamente estou sentindo falta das coisas.

Porém, não parece lento, 123456produz [40 x 3086, 10, 6]quase imediatamente.

Explicação:

Iterando sobre os tamanhos de pepitas (maior primeiro)

  • Se a soma da pilha mais o tamanho da pepita for menor que o objetivo - 3 -> empurre-a em uma pilha
  • Se restarem mais de 40 -> redefina o contador de loop
  • Se a soma da pilha for maior que a meta quando o último tamanho de pepita foi atingido -> pop o último elemento, redefina o contador de loop
  • Se a soma da pilha somar, retorne-a, caso contrário, retorne 0

Para 199 | 1 a pilha construída se parece com isso

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]

Por 1

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

1
Sua abordagem não parece verificar se a meta pode ser alcançada. 11impressões [6]e 18impressões [10, 4].
Dennis

@ Dennis Olá, obrigado por apontar isso. Ontem foi tarde da noite. Corrigido por 5 caracteres. 18 impresso [10,4]porque estava faltando um par de parênteses. A verificação estava realmente errada. Acabei de verificar se havia pelo menos um elemento no conjunto de resultados, e não se ele resume corretamente. Eu não sei o que eu pensei que não
C5H8NNaO4
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.