Vous obtenez une machine avec deux registres 16 bits, x
et y
. Les registres sont initialisés x=1
et y=0
. La seule opération que la machine peut effectuer est l'addition du module 65536. C'est-à-dire:
x+=y
-x
est remplacé par(x + y) mod 65536
;y
est inchangéy+=x
- de même poury
x+=x
-x
est remplacé par2x mod 65536
; légal que six
est pairy+=y
- de même poury
Le but est d'obtenir un nombre prédéterminé dans l'un des registres (soit x
ou y
).
Écrire un programme ou un sous - programme qui reçoit un certain nombre (dans stdin
, argv
, paramètre de fonction, en haut de la pile ou tout autre lieu conventionnel), et délivre un programme pour obtenir ce nombre. La sortie doit aller vers stdout
, ou (si votre langue n'en a pas stdout
) vers tout autre périphérique de sortie conventionnel.
Le programme de sortie peut être jusqu'à 100% plus 2 étapes loin d'être optimal. Autrement dit, si le programme le plus court pour obtenir le nombre cible comporte des n
étapes, votre solution ne peut pas être plus longue que 2n+2
. Cette restriction vise à éviter les solutions "trop faciles" (par exemple compter 1, 2, 3, ...) mais ne nécessite pas une optimisation complète; Je m'attends à ce que le programme le plus court soit le plus facile à trouver, mais je ne peux pas en être sûr ...
Par exemple: Entrée = 25. Sortie:
y+=x
x+=y
x+=y
x+=x
x+=x
x+=x
y+=x
Un autre exemple: pour tout nombre de fibonacci, la sortie a ce modèle alternatif. Pour Input = 21, output est
y+=x
x+=y
y+=x
x+=y
y+=x
x+=y
y+=x
Le code le plus court (mesuré en octets) gagne.
(ce puzzle a été inspiré par du code pour un processeur 16 bits que j'ai dû générer récemment)
PS Je me demande - pour quel numéro le programme optimal est le plus long?
la source
x+=x
légal que s'ilx
est pair? Aussi pour le programme le plus court, je pense que quelque chose comme BFS pourrait fonctionner.x+=x
ne fonctionne que pour lesx
s pairs , comment se fait-il que l'exemple d'une entrée de 25 doubles 3?Réponses:
CJam, 31
Comme la réponse de @Tobia , mon algorithme est également éhonté
voléinspiré par la réponse de @CChak . Mais, brandissant la magie noire qu'est CJam, j'ai réussi à faire une implémentation encore plus petite de l'algorithme.Essayez-le ici.
Golfé:
Non golfé:
Veuillez me corriger si je me trompe, mais je pensais que l'opération modulo 65536 utilisée dans les réponses avec un algorithme similaire n'est pas nécessaire. J'ai interprété la question de telle sorte que nous pouvons supposer que l'entrée sera un entier 16 bits non signé valide, et toutes les valeurs intermédiaires ou les résultats de cet algorithme le seront également.
la source
Perl
10797Premier post, alors voilà.
Ce qui correspond à tous les critères d'ajout de registre, mais je n'ai pas effectué de vérification exhaustive pour voir si ma réponse était toujours à moins de 2n + 2 du nombre optimal d'étapes. Il est cependant bien en deçà de la limite pour chaque numéro de Fibonacci.
Voici une ventilation plus détaillée
Comme je l'ai mentionné, c'est ma première tentative de golf, donc je suis sûr que cela peut être amélioré. De plus, je ne sais pas si l'appel initial du sous-programme doit être compté dans un appel récursif ou non, ce qui pourrait nous faire grimper de quelques caractères.
Fait intéressant, nous pouvons réduire le code de 11 octets * et améliorer notre "efficacité" en termes de nombre d'opérations de registre, en assouplissant l'exigence selon laquelle seules les valeurs paires peuvent être "doublées". Je l'ai inclus pour le plaisir ici:
Commencer l'addendum:
J'ai vraiment aimé ce problème, et je l'ai tripoté de temps en temps au cours des deux dernières semaines. Je pensais publier mes résultats.
Quelques chiffres:
En utilisant un algorithme BFS pour trouver une solution optimale, dans les 2 ^ 16 premiers nombres, seuls 18 nombres nécessitent 23 étapes. Ce sont: 58558, 59894, 60110, 61182, 61278, 62295, 62430, 62910, 63422, 63462, 63979, 64230, 64314, 4486, 64510, 64698, 64854, 65295.
En utilisant l'algorithme récursif décrit ci-dessus, le nombre "le plus difficile" à atteindre est 65535, à 45 opérations. (65534 prend 44, et il y a 14 nombres qui prennent 43 étapes) 65535 est également le plus grand écart par rapport à l'optimal, 45 vs 22. La différence de 23 étapes est 2n + 1. (Seuls trois nombres ont atteint 2n: 65534, 32767, 32751.) À l'exception des cas triviaux (zéro), sur la plage définie, la méthode récursive représente en moyenne 1,4 fois la solution optimale.
Conclusion: pour les nombres 1-2 ^ 16, l'algorithme récursif ne franchit jamais le seuil défini de 2n + 2, donc la réponse est valide. Je soupçonne cependant qu'il commencerait à s'écarter trop loin de la solution optimale pour des registres plus grands / plus de bits.
Le code que j'ai utilisé pour créer le BFS était bâclé, gourmand en mémoire, non commenté et délibérément non inclus. Donc ... vous n'avez pas à faire confiance à mes résultats, mais je suis assez confiant en eux.
la source
Python 3, 202 octets
(Merci à @rationalis pour quelques octets)
Voici une solution extrêmement simple. J'aimerais pouvoir mieux jouer la dernière ligne, mais je suis actuellement à court d'idées. Appelez avec
S(25)
.Le programme ne fait qu'un simple BFS sans mise en cache, il est donc très lent. Voici
S(97)
, pour un exemple de sortie:la source
Dyalog APL, 49 caractères / octets *
Algorithme inspiré sans vergogne par la réponse de @CChak .
Exemple:
Non golfé:
* Dyalog APL prend en charge un jeu de caractères hérité dont les symboles APL sont mappés aux valeurs supérieures de 128 octets. Par conséquent, un programme APL qui utilise uniquement des caractères ASCII et des symboles APL peut être considéré comme des octets == caractères.
la source
Python, 183
Je ne peux pas garantir que cela reste à 2 fois le programme optimal pour les nombres pairs, mais il est efficace. Pour toutes les entrées valides
0 <= n < 65536
, elle est essentiellement instantanée et génère un programme d'au plus 33 instructions. Pour une taille de registre arbitrairen
(après avoir fixé cette constante), cela prendrait duO(n)
temps avec tout au plus des2n+1
instructions.Un peu de logique binaire
N'importe quel nombre impair
n
peut être atteint en 31 étapes: fairey+=x
, obtenirx,y = 1,1
, puis continuer à doublerx
avecx+=x
(pour le premier doublement, fairex+=y
, car ilx
est impair pour commencer).x
atteindra chaque puissance de 2 de cette façon (c'est juste un décalage vers la gauche), et vous pouvez donc définir n'importe quel bit dey
pour être 1 en ajoutant la puissance correspondante de 2. Puisque nous utilisons des registres 16 bits, et chaque bit sauf pour le premier, il faut un doublement pour atteindre et uny+=x
pour mettre, nous obtenons un maximum de 31 ops.Tout nombre pair
n
n'est qu'une puissance de 2, appelez-lea
, multipliez un nombre impair, appelez-lem
; à- diren = 2^a * m
, ou de manière équivalente,n = m << a
. Utilisez le processus ci-dessus pour obtenirm
, puis réinitialisezx
-le en le déplaçant vers la gauche jusqu'à ce qu'il soit à 0. Faites unx+=y
pour définirx = m
, puis continuez à doublerx
, la première foisx+=y
et ensuitex+=x
.Quoi qu'il en
a
soit, il faut des16-a
décalagesx
pour obteniry=m
et desa
décalages supplémentaires pour réinitialiserx=0
. Un autrea
changement dex
se produira aprèsx=m
. Donc, un total de16+a
décalages est utilisé. Il y a jusqu'à des16-a
bits qui doivent être définis pour obtenirm
, et chacun d'entre eux en prendra uny+=x
. Enfin, nous avons besoin d'une étape supplémentairex=0
pour le régler sur mx+=y
,. Il faut donc au maximum 33 étapes pour obtenir un nombre pair.Vous pouvez, bien sûr, généraliser cela à n'importe quel registre de taille, auquel cas il faut toujours au plus
2n-1
et2n+1
ops pour lesn
entiers impairs et pairs, respectivement.L'optimalité
Cet algorithme produit un programme qui est presque optimal (c'est-à-dire dans
2n+2
sin
est le nombre minimum d'étapes) pour les nombres impairs. Pour un nombre impair donnén
, si lem
e bit est le premier 1, alors tout programme prend au moins desm
étapes pour arriver àx=n
ouy=n
, puisque l'opération qui augmente le plus rapidement les valeurs des registres estx+=x
ouy+=y
(c'est-à-dire des doublons) et il faut desm
doublons pour arriver à lem
e bit de 1. Puisque cet algorithme prend au plus des2m
étapes (au plus deux par doublement, une pour le décalage et uney+=x
), tout nombre impair est représenté de façon presque optimale.Les nombres pairs ne sont pas aussi bons, car il utilise toujours 16 opérations pour réinitialiser
x
avant toute autre chose, et 8, par exemple, peuvent être atteints en 5 étapes.Fait intéressant, l'algorithme ci-dessus n'utilise jamais
y+=y
du tout, car ily
est toujours maintenu impair. Dans ce cas, il peut en fait trouver le programme le plus court pour l'ensemble restreint de seulement 3 opérations.Essai
J'ai écrit un test simple pour vérifier que ma solution produit effectivement des résultats corrects, et ne dépasse jamais 33 étapes, pour toutes les entrées valides (
0 <= n < 65536
).De plus, j'ai essayé de faire une analyse empirique pour comparer la sortie de ma solution aux sorties optimales - cependant, il s'avère que la recherche en largeur d'abord est trop inefficace pour obtenir la longueur de sortie minimale pour chaque entrée valide
n
. Par exemple, l'utilisation de BFS pour rechercher la sortie den = 65535
ne se termine pas dans un laps de temps raisonnable. Néanmoins, je suis partibfs()
et je suis ouvert aux suggestions.J'ai cependant testé ma propre solution contre @ CChak (implémentée ici en Python
U
). Je m'attendais à ce que le mien fasse pire, car il est considérablement inefficace pour les petits nombres pairs, mais en moyenne sur toute la plage de deux manières, le mien a produit une production de longueur moyenne de 10,8% à 12,3% plus courte. Je pensais que cela était peut-être dû à une meilleure efficacité de ma propre solution sur les nombres impairs, doncV
utilise le mien sur les nombres impairs et @ CChak sur les nombres pairs, mais seV
situe entre les deux (environ 10% plus court queU
, 3% plus long queS
).la source
x,y='xy'
c'était possible jusqu'à présent. Malheureusement, je ne peux pas penser à un moyen de réécrire de manièrec*b+e*2
concise avec le%
formatage.S(2)
la sortie est-elle vraiment longue?S(2)
étant la plus courte à 19). Je ne garde pas de tracex
ety
explicitement, donc même s'ilx
atteint 2 après la deuxième étape, il continue néanmoins de se remettrex
à 0. Je pense qu'il doit y avoir une meilleure solution, mais pour l'instant je ne peux pas penser à un.