Huit pièces pour le juste roi


22

Ceci est une "contrepartie" d'un autre puzzle, Huit pièces pour le beau roi sur Puzzling.SE.

Vous pouvez lire le puzzle ci-dessus pour le fond. Les détails de ce puzzle sont les suivants.

Un ensemble de 8 types de pièces de valeurs différentes est créé, le roi veut que vous trouviez le N maximum de sorte que n'importe quel nombre de prix de 0 à N puisse être payé avec une combinaison pas plus de 8 pièces et sans frais.

Par exemple, (tiré de la réponse de Glorfindel). Si un ensemble de pièces de valeurs 1, 2, 5, 13, 34, 89, 233, 610 est donné, votre programme devrait afficher 1596, car chaque nombre compris entre 0 et 1596 (inclus) peut être représenté par la somme de pas plus de 8 numéros de la liste donnée (les chiffres peuvent se répéter), tandis que 1597 ne peut pas être représenté de cette façon.

De manière mathématique, si l'entrée est un ensemble S composé de 8 entiers positifs, la sortie souhaitée N vérifie que pour tout nombre n compris entre 0 et N, il existe x1, x2, x3, ..., x8 tels que

x1+x2+...+x8=nandx1,x2,...,x8{0}S

Votre objectif est d'écrire un programme, une fonction ou un extrait de code qui prend 8 chiffres en entrée et de sortir le N maximum comme décrit ci-dessus.

Règles:

  • E / S flexibles autorisées, afin que votre programme puisse prendre l'entrée sous la forme qui convient le mieux. Vous pouvez supposer que les numéros d'entrée sont triés de la manière qui convient le mieux à votre programme.
    • Veuillez l'indiquer dans votre réponse si votre programme dépend de l'ordre d'entrée
  • L'entrée est un ensemble de 8 entiers positifs différents (pas de zéros). La sortie est un entier non négatif.
    • Dans le cas où il n'y a pas de 1 dans le jeu d'entrée, votre programme devrait sortir 0 car tout nombre de 0 à 0 satisfait à l'exigence.
    • Dans le cas d'une entrée invalide (l'ensemble contient zéro, des nombres négatifs ou en double), votre programme peut tout faire.
  • Les failles standard sont interdites.
  • Votre programme devrait s'exécuter en quelques minutes sur un ordinateur moderne.

Cas de test (principalement tirés des réponses sous la question liée sur Puzzling):

[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

C'est un , donc le programme ou l'extrait le plus court dans chaque langue gagne!


1
Joli puzzle, mais je pense personnellement que d'autres cas de test seraient utiles afin de tester nos soumissions.
M. Xcoder

Ne serait-il pas préférable de faire de la taille d'entrée un paramètre? Les approches de force brute auront du mal avec 8
Luis Mendo

1
@iBug Alors la règle habituelle est quelque chose comme "les soumissions doivent être exécutées en une minute dans un ordinateur moderne". C'est flou, mais généralement assez bon, car la différence entre la force brute et les approches efficaces est très grande
Luis Mendo

1
La force brute est toujours possible avec votre limite de temps de "quelques minutes". Une version légèrement modifiée de ma réponse exécute le dernier cas de test en 1m20 sur mon ordinateur portable de 7 ans.
nimi

1
@Arnauld Clarified
iBug

Réponses:



9

Gelée , 12 octets

œċⱮ8Ẏ§ṢQJƑƤS

Essayez-le en ligne!

Prend en moyenne ~ 3,7 secondes pour exécuter tous les cas de test sur TIO sur mon téléphone, donc c'est assez rapide.

Explication

œċⱮ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 octets

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

Essayez-le en ligne!

Une approche par force brute. Ajoutez 0à la liste des pièces et essayez toutes les combinaisons de 8 choix. Trouvez le premier nombre nqui n'est pas égal à la somme des choix et retournez n-1.

Prend environ 5m30 pour [1, 2, 5, 13, 34, 89, 233, 610]mon ordinateur portable de 7 ans.

Edit: -6 octets grâce à @ Ørjan Johansen

Une version encore plus courte (-2 octets, encore grâce à @ Ørjan Johansen) est

Haskell, 48 octets

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

mais il utilise beaucoup plus de mémoire et se heurte à une pagination importante sur ma machine et ne se termine pas "en quelques minutes".


1
Vous pouvez utiliser mapM(0:)$c<$c. (En fait, cela mapM(:0:c)cdevrait fonctionner, mais expire sur TIO pour le cas de test donné.)
Ørjan Johansen

4

Gelée , 9 octets

Żœċ8§ḟ’$Ṃ

Essayez-le en ligne!

Comment ça marche

Żœċ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§ḟ’$Ṃenregistre un octet, mais je ne sais pas si 8,5 minutes comptent pour quelques .
Dennis


4

JavaScript (ES6),  100 88 80  76 octets

Il s'agit essentiellement d'une recherche par force brute, mais améliorée par l'élagage pour l'accélérer. Le temps d'exécution moyen des cas de test est proche de 1 seconde sur TIO.

Suppose que le tableau d'entrée est trié du plus élevé au plus bas.

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

Essayez-le en ligne!

Commenté

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

Pari / GP , 57 octets

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

Essayez-le en ligne!


est-ce en utilisant la fonction de génération?
Don Bright

1
@donbright Oui.
Alephalpha

1
c'est génial .. une des rares réponses qui ne force pas brutalement la solution. beaucoup de langues n'ont probablement pas intégré de caractéristiques symboliques polynomiales. Pari GP est cool.
Don Bright le

2

Python 2 , 125 115 111 111 octets

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

Essayez-le en ligne!

Attend une liste d'entiers en entrée.

Explication:

# 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 octets ( 39 37 caractères)

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

Essayez-le en ligne!

Il s'agit d'un bloc anonyme qui reçoit ses données sous forme de tableau. Le (0,|@_)est un moyen rapide d'ajouter un 0à @_, et même s'il est fait deux fois, il est toujours un peu plus court que celui @_.push: 0;qui aurait alors besoin d'espaces après le _. Il s'agit d'une approche de force brute qui fromages un peu sur le fait qu'il s'agit de 8 combinaisons. Après l'ajout croisé, une liste anonyme est créée pour les valeurs séquentielles. Avec les opérateurs mathématiques, les listes sont évaluées en fonction de leur longueur, donc le -1 tire le double devoir: tenir compte du 0 et contraindre à Int.

Cela peut prendre son temps doux, mais en changeant un ou les deux (0,|@_)à (0,|@_.unique)avant la première , foril peut être accéléré considérablement. Cela ajoute +7 (runtime <60s) ou +14 (runtime <10s) au score si vous sentez que le premier est trop lent (je l'ai fait pour le code lié pour éviter les délais d'attente après 60 secondes).

Edit: JoKing dans les commentaires l'a amélioré (même idée, cross add, puis retourne le dernier résultat consécutif) à un étonnant 39 caractères (41 octets):

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

Essayez-le en ligne!

La tabulation finale n'a pas besoin d'un 0, économisant quelques octets en n'ayant besoin que d'ajouter 0 en une fois. Le xx 3mime la boucle for (les fromages encore sur les pièces étant une puissance de 2). Le firstsous retourne le premier nombre de la liste infinie 0..*( ^Infest également possible, mais n'économise pas d'espace) dont il +1n'est pas membre de la liste croisée. Comme le mien, c'est lent, alors ajoutez +7 pour un uniqueaprès le premier égal si vous pensez que c'est trop lent pour les directives.


1
48 octets . Techniquement, le uniquen'est pas nécessaire, mais cela l'accélère beaucoup
Jo King

@JoKing nice, je ne sais pas pourquoi je n'ai pas pensé à utiliser xx. Je savais qu'il devait y avoir un moyen de faire la tabulation finale d'une manière beaucoup plus courte en utilisant des fonctions définies, mais mon cerveau ne fonctionnait pas.
user0721090601

Le xx 1devrait êtrexx 3
Jo King

@JoKing corrigé. J'ai également réalisé que deux caractères (mais pas d'octets) pouvaient être enregistrés en utilisant^∞
user0721090601

En fait, vous pouvez enregistrer quelques octets avec (1...*∉@_)-1au lieu d'utiliser first, (ce que je réalise est la même méthode que j'ai utilisée ici )
Jo King

1

JavaScript (Node.js) , 171 145 115 octets

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

Essayez-le en ligne! Port de @ Mark's Python 3 answer. 108 octets dans 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 octets

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

Essayez-le en ligne!

Approche de la force brute: vérifie les nombres entiers en comptant vers le haut jusqu'à ce qu'ils atteignent une valeur qui ne peut pas être payée en 8 pièces. Très, très lent (tio expire), mais je suis assez sûr que la condition est correcte.


0

Nettoyer , 161 octets

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

Essayez-le en ligne!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.