Pépites de code

18

Pépites de code

C'est une situation hypothétique où c'est vendredi soir, et vous avez invité les copains de golf habituels à participer à votre passe-temps préféré: le golf à code. Cependant, comme il s'agit d'une tâche épuisant pour le cerveau, vous devez ramasser de la nourriture pour le cerveau du groupe afin de pouvoir jouer au golf autant que possible en dehors de votre code.

Maintenant, la collation préférée de tout le monde est les pépites de poulet, mais il y a un problème: il n'y a pas de paquet unique qui couvre les besoins de chacun. Donc, comme vous êtes déjà d'humeur golfique, vous décidez de créer un programme qui détermine exactement quels packs vous devez acheter pour pouvoir couvrir les besoins de chacun.

Les tailles de pépites de poulet sont partout, et selon l'endroit où vous vivez dans le monde, les tailles standard changent également. Cependant, [l'endroit qui sert les pépites] le plus proche stocke les tailles suivantes de packs de pépites :

4, 6, 9, 10, 20, 40

Vous pouvez maintenant remarquer que vous ne pouvez pas commander certaines combinaisons de pépites. Par exemple, les 11pépites ne sont pas possibles, car il n'y a pas de combinaison 11exactement égale . Cependant, vous pouvez faire 43en obtenant 1 pack de 20, 1 pack de 10, 1 pack de 9et 1 pack de 4,

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

597chaque terme est quadrillé et additionné (indice: la solution optimale a cette valeur la plus élevée) . Il existe bien sûr d'autres façons de fabriquer 43, mais comme vous le savez, plus il y a de pépites par paquet, moins c'est cher par pépite. Ainsi, vous souhaitez idéalement acheter le moins de packs et en plus grandes quantités pour minimiser vos coûts.

La tâche

Vous devez créer un programme ou une fonction qui prend une liste d'entiers correspondant aux exigences de chaque personne. Vous devez ensuite calculer et imprimer la commande α la plus rentable pour acheter les pépites de poulet. L' ordre α le plus rentable est la combinaison par laquelle la somme des carrés de chaque quantité est la plus élevée. S'il n'y a absolument aucun moyen d'acheter les pépites parfaitement, vous devez imprimer une valeur falsy telle que 0, False, Impossible!ou tout ce qui est disponible dans votre langue.

Exemple d'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!

Voici la liste des solutions idéales pour les 400 premiers. Notez que celles-ci ne sont pas formatées comme je m'y attendrais, chacune tupleest sous la forme (N lots of M).

Règles

  1. Pas de failles standard.
  2. Aucune utilisation des fonctions intégrées qui effectuent la totalité ou la majorité de la tâche, comme FrobeniusSolvedans Mathematica.

α - Pour clarifier cela avec un exemple, vous pouvez également faire 43 en faisant 4 + 6 + 6 + 9 + 9 + 9 = 43 (319), mais ce ne serait pas optimal, et donc une sortie incorrecte, car la somme des carrés est inférieure à la combinaison que j'ai notée dans l'introduction. Essentiellement, somme de carrés plus élevée = coût inférieur = plus rentable.

Kade
la source
Y a-t-il des limites de temps / mémoire?
Dennis
@Dennis Il n'y a pas de limite de temps ou de mémoire.
Kade
4
C'est en fait jeudi.
mbomb007
4
@ mbomb007 Observation astucieuse: P J'ai ajusté l'intro.
Kade
2
J'AI BESOIN d'utiliser le théorème du poulet mcnugget d'une manière ou d'une autre ...
Stretch Maniac

Réponses:

7

Pyth, 26 25 octets

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

Notez qu'il existe des caractères non imprimables. Essayez-le en ligne: démonstration . C'est assez lent (mais pas aussi lent que ma solution de 26 octets).

Explication:

                          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 octets

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

Notez qu'il existe des caractères non imprimables. Essayez-le en ligne: Démonstration Cette version est beaucoup plus rapide. Il trouve la solution pour l'entrée [6,7,8]en environ une seconde et la solution pour l'entrée [30]en environ 90 secondes.

Explication:

                                 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
Jakube
la source
Pourquoi est-ce par le carré de la somme des carrés, plutôt que simplement par la somme?
mbomb007
1
@ mbomb007 Parce que cela n'a pas d'importance. Si a> b, alors sqrt (a)> sqrt (b) et vice versa. Et l'utilisation de la .améthode est plus courte que la quadrature et la sommation 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":(";}

Prend son entrée à partir des arguments du programme. Imprime un :( s'il ne trouve pas de solution parfaite.

Code non golfé:

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: C'est probablement la première entrée qui ne prend pas 10 minutes 1 2;)

Vérifiez le ici.

Thomas Oltmann
la source
Félicitations pour ce qui semble être le programme le plus rapide à ce jour! Il pourrait également être plus rapide que mon programme de référence: P J'ai ajouté un lien idéone au bas de votre message pour que les gens puissent voir le résultat.
Kade
Votre code peut produire une sortie incorrecte. L'entrée 18doit s'imprimer 9 9, non 4 4 10.
Dennis
Il existe également d'autres sorties incorrectes. Si je ne me trompe pas, vous pouvez tous les corriger en changeant l'ordre de 9et 10.
Dennis
@Dennis Merci, corrigé!
Thomas Oltmann
3

CJam, 45 29 28 octets

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

Notez que cette approche est très lente et gourmande en mémoire.

Essayez-le en ligne dans l' interpréteur CJam .

Il peut être accéléré de manière significative au prix de 5 octets:

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

La complexité est toujours exponentielle dans la somme des entrées, mais cela devrait gérer des cas de test jusqu'à 159 avec l'interpréteur en ligne et jusqu'à 199 avec l'interpréteur Java en quelques secondes.

Essayez-le en ligne dans l' interpréteur CJam .

Idée

Un achat optimal (somme maximale des carrés) est un achat valide (nombre correct de pépites) qui a autant de 40 que possible, puis autant de 20 que possible, puis autant de 9 que possible (par exemple, 9 9est préférable à 10 4 4) et ainsi de suite pour 10 , 6 et 4 .

Dans cette approche, nous générons le produit cartésien de N copies du tableau [40 20 9 10 6 4 0] , où N est le nombre souhaité de pépites. N est une (mauvaise) limite supérieure pour le nombre d'achats que nous devons effectuer. Dans la version accélérée du code, nous utilisons à la place N / 40 + 4 .

En raison de la façon dont le tableau est ordonné, le produit cartésien commencera par le vecteur [40 ... 40] et se terminera par le vecteur [0 ... 0] . Nous calculons l'index du premier vecteur qui a la somme correcte (qui aura également la somme optimale des carrés), récupérons l'élément de tableau correspondant, supprimons les zéros qui ont servi d'espaces réservés et imprimons le résultat.

Si aucun vecteur n'a pu être trouvé, l'indice sera -1 , nous récupérons donc [0 ... 0] , qui affichera un tableau vide à la place.

Code

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.
Dennis
la source
Cela peut être l'une des rares situations où l'élaboration de la solution à la main serait plus rapide que de laisser le code se terminer .. beau travail malgré tout :)
Kade
2

Julia, 126 octets

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

Cela crée une fonction sans nom qui accepte un tableau en entrée et imprime un tableau ou un booléen sur STDOUT, selon qu'il existe une solution. Pour l'appeler, donnez-lui un nom, par exemple f=n->....

Non golfé + explication:

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

Exemples:

julia> f([1])
false

julia> f([2,7,12,4,15,3])
[20,10,9,4]
Alex A.
la source
1

Python 3 - 265 caractères

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)

Affichage de l'espacement:

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)

Réussit tous les cas de test

Remarque: Je ne sais pas si cela passera tous les cas car c'est si lent ... Mais ça devrait ...

Beta Decay
la source
Rien ne semble mal avec ça en ce moment, je vais le tester et voir. Une fois à la maison, je vais ajouter une référence, un programme non golfé que j'ai utilisé pour générer la liste qui est dans le Gist. Bien que je ne chronomètre pas, je pense que cela a pris quelque part dans la plage de 8 à 12 minutes pour tous les cas.
Kade
@ Vioz- Brilliant! : D
Beta Decay
On dirait que je peux me tromper, après avoir testé 36, il obtient environ 40 millions de combinaisons (40 007 602 pour être exact) avant de se heurter à une erreur de mémoire. Cela pourrait être une limitation de ma machine de travail, car elle n'a que 4 Go de mémoire.
Kade
@ Vioz- Hm ... Eh bien, c'est sans espoir pour moi de continuer les tests sur mon téléphone ...
Beta Decay
1
@undergroundmonorail Si vous ne l'utilisez qu'une seule fois, alors pour <= 4 caractères, une importation directe est meilleure (5 points même). Mais si vous l'utilisez plus d'une fois, from blah import*c'est toujours mieux. La seule exception à laquelle je peux penser pour ce qui précède est que si vous avez plusieurs imports, c'est le seul moment qui me vient à l'esprit où asest réellement utile.
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

Je ne sais pas si cela va bien, cela semble fonctionner mais je manque sûrement des choses.

Il ne semble pas être lent cependant, jusqu'à 123456ce qu'il produise[40 x 3086, 10, 6] presque immédiatement.

Explication:

Itération sur la taille des pépites (la plus grande en premier)

  • Si la somme de la pile plus la taille de la pépite est inférieure à l'objectif - 3 -> poussez-la sur une pile
  • S'il en reste plus de 40 -> réinitialiser le compteur de boucle
  • Si la somme de la pile est supérieure à l'objectif lorsque la dernière taille de pépite a été atteinte -> éclater le dernier élément, réinitialiser le compteur de boucle
  • Si la somme de la pile s'additionne, retournez-la, sinon retournez 0

Pour 199 | 1 La pile construite ressemble à ceci

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]

Pour 1

i | stack
0   []
1   []
2   []
3   []
4   []
5   []
==> 0
C5H8NNaO4
la source
1
Votre approche ne semble pas vérifier si l'objectif peut être atteint. 11imprime [6]et 18imprime [10, 4].
Dennis
@Dennis Salut, merci de l'avoir signalé. Il a été tard hier soir. Correction de 5 caractères. 18 imprimé [10,4]parce qu'il me manquait une paire de parens. La vérification était en effet erronée, je viens de vérifier s'il y avait au moins un élément dans l'ensemble de résultats, pas s'il résume correctement. Je ne sais pas ce que j'y pensais
C5H8NNaO4