Avec un entier positif N , votre tâche consiste à renvoyer le nombre d'étapes requis par l'algorithme suivant pour atteindre N :
Trouvez le nombre le plus petit triangle T i tel que T i ≥ N . Construisez la liste correspondante L = [1, 2, ..., i] .
Bien que la somme des termes de L soit supérieure à N , supprimez le premier terme de la liste.
Si la somme des termes de L est maintenant inférieure à N , incrémentez i et ajoutez-le à la liste. Continuez avec l'étape # 2.
Nous nous arrêtons dès que N est atteint. Seule la première étape est systématiquement exécutée. Les étapes 2 et 3 peuvent ne pas être traitées du tout.
Exemples
Voici un exemple pour N = 11 :
La sortie attendue pour N = 11 est donc 4 .
Autres exemples:
- N = 5 - On commence avec T 3 = 1 + 2 + 3 = 6 , suivi de 2 + 3 = 5 . Résultats attendus: 2 .
- N = 10 - Seule la première étape est requise car 10 est un nombre triangulaire: T 4 = 1 + 2 + 3 + 4 = 10 . Résultats attendus: 1 .
100 premières valeurs
Voici les résultats pour 1 ≤ N ≤ 100 :
1, 2, 1, 4, 2, 1, 2, 10, 2, 1, 4, 2, 6, 2, 1, 22, 8, 2, 10, 2,
1, 2, 12, 6, 2, 4, 2, 1, 16, 2, 18, 50, 2, 6, 2, 1, 22, 6, 2, 4,
26, 2, 28, 2, 1, 8, 30, 16, 2, 6, 4, 2, 36, 2, 1, 2, 4, 12, 40, 2,
42, 14, 2,108, 2, 1, 46, 2, 6, 4, 50, 2, 52, 18, 2, 4, 2, 1, 56, 12,
2, 20, 60, 4, 2, 22, 10, 2, 66, 2, 1, 4, 10, 24, 2, 40, 72, 8, 2, 6
Règles
- Vous pouvez écrire un programme complet ou une fonction qui imprime ou renvoie le résultat.
- Vous devez traiter une N ≤ 65536 en moins d'une minute sur le matériel de milieu de gamme.
- Avec suffisamment de temps, votre programme / fonction devrait théoriquement fonctionner pour toute valeur de N supportée nativement par votre langue. Si ce n'est pas le cas, veuillez expliquer pourquoi dans votre réponse.
- C'est le code de golf, donc la réponse la plus courte en octets gagne!
code-golf
math
integer-partitions
Arnauld
la source
la source
Réponses:
Gelée ,
29 à31 octetsUn lien monadique qui renvoie le résultat (N = 65536 prend moins de deux secondes).
Essayez-le en ligne!
Comment?
Pour une explication détaillée de l'algorithme, voir l'article fantastique de Martin Ender .
L’implémentation de programme complet de 29 octets que j’ai créée de l’algorithme décrit prend 4 min 30 pour N = 65536 sur mon ordinateur portable; je suppose donc que cela ne compte pas.
Utiliser une boucle while pour chaque étape 3 et la réutiliser en tant qu'étape 1 a la même longueur que ce que je peux gérer avec l'initialisation de la liste car l'absence de vérification à l'étape 3 signifie construire une liste jusqu'à ce qu'il ne reste plus rien, puis trouver le premier index de la valeur:
la source
Mathematica, 79 octets
Explication
Je ne pouvais pas être dérangé pour implémenter l'algorithme dans le défi, alors je voulais chercher un raccourci vers la solution. Bien que j'en ai trouvé un, malheureusement, il ne bat pas la réponse de Mathematica qui implémente l'algorithme. Cela dit, je suis sûr que le jeu n’est pas encore optimal et que d’autres langues pourraient bénéficier de cette approche ou de certaines des connaissances acquises au cours du processus.
Je prétends donc que la séquence que nous sommes supposés calculer est la suivante:
f (n) = 2 * ( A212652 (n) - A002024 (n)) + 1 + A023532 (n-1)
Sinon, c'est f (n) = 1 si n est un nombre triangulaire et f (n) = 2 * ( A212652 (n) - A002024 (n) + 1) sinon.
Dans la première expression, A023532 code simplement ces deux cas différents. Les deux autres séquences (plus 1) représentent la différence entre le plus grand entier k de la plus longue décomposition de n en entiers consécutifs (k-i + 1) + (k-i + 2) + ... + k = n et le plus grand entier j tel que 1 + 2 + ... + j <n .
En termes plus simples, voici comment trouver la réponse aux nombres non triangulaires: premièrement, trouvez le plus grand nombre triangulaire T j qui est inférieur à n . Alors j est l’avant-dernier nombre entier ajouté lors de l’étape 1 (car après avoir ajouté j + 1, nous aurons dépassé n ). Décomposez ensuite n en autant d’entiers consécutifs que possible (ou le plus petit possible) et appelez le maximum parmi ces nombres k . Le résultat est simplement 2 * (kj) . La raison intuitive en est que le maximum dans la décomposition augmente de 1 à chaque étape et nous nous arrêtons lorsque nous atteignons.k .
Nous devons montrer quatre choses pour prouver que cela fonctionne:
Nous avons déjà montré pourquoi (1) est vrai. Ensuite, nous prouvons que nous ne pouvons pas terminer sur une étape d’insertion à l’exception de la première (ce qui n’arrive pas pour les nombres non triangulaires).
Supposons que nous terminions sur une étape d'insertion, atteignant n après avoir ajouté une valeur p à la somme. Cela signifie qu'avant cette étape d'insertion, la valeur était np ( ou inférieure si nous ajoutions plusieurs valeurs à la fois). Mais cette étape d’insertion a été précédée d’une étape de suppression (nous n’aurions pas pu toucher n lors de l’étape 1). La dernière valeur q que nous avons supprimée au cours de cette étape de suppression était nécessairement inférieure à p en raison du fonctionnement de l'algorithme. Mais cela signifie que, avant de retirer q, nous avions n-p + q ( ou moins ), ce qui est inférieur à n. Mais ce qui est une contradiction, parce que nous aurions dû arrêter la suppression des entiers lorsque nous avons atteint n-p + q au lieu d'enlever une autre q . Cela prouve le point (2) ci-dessus. Nous savons donc maintenant que nous terminons toujours par une étape de suppression et que, par conséquent, tous les nombres non triangulaires ont des sorties paires.
Ensuite, nous prouvons (3) que chaque étape d’insertion ne peut insérer qu’une valeur. Ceci est essentiellement un corollaire de (2). Nous avons montré qu'après avoir ajouté une valeur, nous ne pouvions pas atteindre n exactement et puisque la preuve utilisait une inégalité, nous ne pouvions pas non plus nous retrouver sous n (depuis lors, n-p + q serait toujours inférieur à n et nous n'aurions pas dû être supprimés). autant de valeurs en premier lieu). Donc, chaque fois que nous ajoutons une seule valeur, nous sommes assurés de dépasser n parce que nous sommes passés en dessous de n en supprimant une valeur plus petite. Par conséquent, nous savons que la partie supérieure de la somme augmente de 1 à chaque étape. Nous connaissons la valeur initiale de cette extrémité supérieure (c’est le plus petit m tel queT m > n ). Maintenant, il ne nous reste plus qu'à déterminer cette limite supérieure une fois que nous aurons atteint la somme finale. Ensuite, le nombre d'étapes est simplement le double de la différence (plus 1).
Pour ce faire, nous prouvons (4) que la somme finale est toujours la décomposition de n en autant d’entiers que possible, ou la décomposition où le maximum de cette décomposition est minimal (c’est-à-dire la décomposition la plus précoce possible). Nous le ferons à nouveau par contradiction (le libellé de cette partie pourrait être un peu plus rigoureux, mais j'ai déjà passé beaucoup trop de temps à ce sujet ...).
Disons que la décomposition la plus ancienne / la plus longue possible de n est un peu a + (a + 1) + ... (b-1) + b , a ≤ b , et que l'algorithme la saute. Cela signifie qu'au moment où b est ajouté, a ne doit plus faire partie de la somme. Si a faisait partie de la somme s , alors nous aurions n ≤ s à ce moment. Donc soit la somme ne contient que les valeurs de a à b , ce qui équivaut à n et nous nous arrêtons (par conséquent, nous n'avons pas ignoré cette décomposition), ou bien il existe au moins une valeur inférieure à a dans la somme, gagner auquel cas n <set cette valeur serait supprimée jusqu'à ce que nous atteignions la somme exacte (encore une fois, la décomposition n'a pas été ignorée). Il faudrait donc nous débarrasser de a avant d’ajouter b . Mais cela signifie que nous devrions atteindre une situation dans laquelle a est la plus petite composante de la somme, et la plus grande n'est pas encore b . Cependant, à ce stade, nous ne pouvons pas supprimer a , car la somme est clairement inférieure à n (puisque b est manquant), nous devons donc ajouter des valeurs en premier jusqu'à ce que nous ajoutions b et n exactement. Cela prouve (4).
Donc, en prenant ces choses ensemble: nous savons que la première paire d’étapes nous donne une valeur maximale de A002024 (n) . Nous savons que la valeur maximale de la décomposition finale est A212652 (n) . Et nous savons que ce maximum est incrémenté une fois par paire. Par conséquent, l'expression finale est 2 * ( A212652 (n) - A002024 (n) + 1) . Cette formule fonctionne presque pour les nombres triangulaires, sauf que pour ceux-ci nous avons seulement besoin d'un pas, c'est pourquoi nous corrigeons le résultat avec la fonction indicatrice des nombres triangulaires (ou son inverse, selon ce qui convient le mieux).
Enfin, quant à la mise en œuvre. Pour la première séquence, j'utilise la formule MIN (impaire d | n; n / d + (d-1) / 2) d'OEIS. Il s'avère économiser quelques octets si nous prenons le facteur 2 dans cette expression pour obtenir MIN (impair d | n; 2n / j + d-1) , car -1 s'annule alors avec le +1 dans ma première version de f (n) qui code directement les deux cas pour les nombres triangulaires et non triangulaires. Dans le code, c'est:
Pour cette dernière séquence (
1, 2, 2, 3, 3, 3, ...
), nous pouvons utiliser un formulaire fermé simple:Enfin, la fonction indicatrice inverse des nombres triangulaires est 0 lorsque 8n + 1 est un carré parfait. Ceci peut être exprimé dans Mathematica comme
Il y a beaucoup de façons d'exprimer ces deux dernières séquences et de décaler un décalage constant entre elles. Je suis donc certain que cette implémentation n'est pas encore optimale, mais j'espère que cela pourrait donner à d'autres un point de départ pour explorer de nouvelles approches. leurs propres langues.
Depuis que je suis allé à tous ces problèmes, voici un graphique de la séquence allant jusqu'à n = 1000 (je pourrais aussi calculer 100k en quelques secondes, mais cela ne montre pas vraiment d'informations supplémentaires):
Il serait peut-être intéressant d'examiner les variations à propos de ces lignes très droites, mais je laisserai cela à quelqu'un d'autre ...
la source
Mathematica, 72 octets
Fonction pure prenant un argument entier.
Comment ça marche
Une
For
boucleInitialisation; définir
l
(inférieur),u
(supérieur),c
(compteur) etk
(somme) sur 0.État; répéter tant que
k
n'est pas égal à l'entrée.Incrément; incrémenter le compteur
c
.Corps
Si l'entrée est supérieure à
k
:Tant que l'entrée est supérieure à
k
, incrémenteru
et incrémenterk
deu
.Si l'entrée n'est pas supérieure à
k
:Alors que l'entrée est inférieure
k
, décrémentk
parl
et incrémentl
.Retour
c
après la boucle.la source
For[,...]
beatsWhile[...]
.Python 2 , 104 octets
Essayez-le en ligne!
Alterner entre l'ajout de termes à la fin de la liste et la suppression de termes au début.
la source
Haskell ,
70 63 6864 octetsMODIFIER:
a
. Correction des erreurs par une dans l'explication.a
etb
linéairement pour que les termes de la formule de sommation soient annulés.1#1
est une fonction anonyme prenant et renvoyant un entier.Utiliser comme
(1#1) 100
.Essayez-le en ligne!
Comment ça marche
(a#b)n
représente l'étape actuelle du calcul.a, b
sont des nombres1, 3, 5, ..
, alors quen
peuvent être positifs ou négatifs selon l’étape.[(a+1)/2,(a+3)/2..(b-1)/2]
et le numéro d'objectif-n
.[(b+1)/2,(b+3)/2..(a-1)/2]
et le numéro d'objectifn
.a, b
et les listes permet de faire la somme avec l'expression courtes=a*a-b*b
.s= -8*sum[(a+1)/2..(b-1)/2]
.s=8*sum[(b+1)/2..(a-1)/2]
.s>8*n
, alorsb
est incrémenté de 2 avant la récursivité.s<8*n
, puis récursion change l'étape en échangeanta
etb
, et la négationn
, et 1 est ajouté au résultat.s==8*n
, alors aucune des deux compréhensions de liste ne donne d’éléments, la somme est donc0
.(1#1) n
représente une "étape 2" factice avant de commencer, qui passe immédiatement à l’étape 1, qui construit la liste[1..0]=[]
.la source
PHP> = 7.0, 74 octets
utiliser l' opérateur du vaisseau spatial
Essayez-le en ligne!
Étendu
la source
$argn
?-R
beaucoup moinsargv
ouargi
. Je connaissais argc et argv bien sûr. Très intéressant, merci.C,
9491 octetsEssayez en ligne
la source
return
), mais pour ceux qui le font, n'hésitez pas à les intégrer à votre réponse.JavaScript (ES6), 82 octets
Test Snippet
Afficher l'extrait de code
la source
dc , 61 octets
Essayez-le en ligne!
Explication
Macro récursive principale:
Cette macro:
S
représente le nombre actuel exactement. Quitte si c'est le cas.S+N
(sur-approximation) ouS-N
(sous-approximation), le choix alterne entre les itérations.Quand il sort, la trace laissée sur la pile indique au programme principal le nombre d’itérations qu’il a pris.
la source
Python 3,
150138 octetsChangelog:
la source
else
est nécessaire? Je crois que leselse
exécutions à chaque fois, parce que la boucle se termine toujours normalement (sansbreak
), et elle semble fonctionner correctement sans cela .A=l.append
pièce et l'utiliser à lal+=[x]
place.Lot, 126 octets
Explication:
l
est zéro si l'étape 2 n'a jamais été exécutée. Cela permetn
de suivre le nombre d'itérations de l'étape 3. Etant donné que l'algorithme ne s'arrête jamais à l'étape 3, il doit donc avoir exécuté l'étape 1 une fois et l'étape 2n+1
fois pour un total d'n+n+2
étapes. Toutefois, si le paramètre est un nombre triangulaire, l’étape 2 ne s’exécutant jamais, il faut soustraire une étape.la source
Python 2,
8681 octetsEssayez-le en ligne!
Calcule le scénario de test 65536 dans
0.183s
TIO.Cette version récursive à 84 octets ne permet pas de calculer toutes les valeurs jusqu'à 65 536:
Essayez-le en ligne!
la source
Mathematica, 92 octets
Fonction pure prenant un argument entier et renvoyant un entier.
Les variables
a
etb
représentent les nombres de début et de fin (en constante évolution) dans la somme considérée, tandis queq
représente le total cumulé (des nombres dea+1
àb
);t
garde la trace de toutes les valeursq
rencontrées jusqu'à présent. Après l’initialisation de ces variables, laFor
boucle continue de s’exécuterIf[q<#,q+=++b,q-=++a]
, ce qui ajoute un nouveau nombre à la fin ou soustrait le nombre situé au premier rang, comme le spécifie la spécification, jusqu’à ce queq
l’entrée soit égale.Il ne reste plus qu’à extraire le nombre d’étapes
t
, la liste desq
valeurs rencontrées. Par exemple, lorsque l'entrée est11
, laFor
boucle se termine avect
égalisation{0,1,3,6,10,15,14,12,9,15,11}
. Le meilleur moyen que j’ai trouvé de calculer le nombre d’étapes à partir de ceci est de compter combien de fois les différences passent d’une baisse à une autre; c'est ce que la commande verbeuseLength@Split@Sign@Differences@t
fait, mais je suppose que cela peut être amélioré.la source
C (tcc), 71 octets (61 + 10)
Arguments en ligne de commande (y compris un espace):
La source:
Comment ça marche:
c
compte le nombre d'étapes.m
etM
stocker le minimum et le maximum de la plage,s
la somme. Au départ, ils sont tous nuls.Continue,
c
est augmenté, ets
est comparé àn
. Tant qu'ils sont inégaux:Si
c
est impair, alors tant ques<n
, ajoutez un entier à la fin de la plage: augmentezM
de un ets
deM
.Si
c
est encore, alors tant ques>n
, supprimer un nombre entier depuis le début de la plage: diminutions
dem
, et d' augmenterm
par un.Lorsque la boucle sort,
c
a été augmentée une fois de trop. La décrémentation produit le résultat correct et elle est calculée dans le registre correct pour servir de valeur de retour.Il arrive de façon amusante d’utiliser exactement le même nom de variable que la réponse C de Khaled.K . Ils ne sont pas copiés.
la source
Perl 6 , 114 octets
(inspiré d'une implémentation antérieure de Haskell )
Essayez-le
Il fonctionne avec une entrée de 65 536 en moins de 45 secondes sur mon ordinateur, mais je n'ai pas réussi à le faire fonctionner en moins de 60 secondes avec TIO.run.
J'ai Rakudo v2017.04 +, où il a v2017.01 .
Rakudo / NQP / MoarVM étant optimisé presque tous les jours, un nombre quelconque d'entre elles pourraient être nécessaires entre-temps pour l'intégrer plus rapidement.
Étendu
Notez que Rakudo a une optimisation pour
Range.sum
ne pas avoir à parcourir toutes les valeurs.la source