Représentation la plus courte d'un numéro de sous-charge


13

Texte de saveur

L'esolang Underload basé sur la pile a des liens intéressants avec la programmation fonctionnelle. L'un d'eux est son traitement du type de données numérique - comme le calcul lambda, vous représentez le nombre naturel N par une fonction qui effectue une action N fois.

Pour simplifier les choses, nous ne considérerons que le sous-ensemble suivant de commandes Underload:

  • : - Cette commande duplique l'élément supérieur de la pile.
  • * - Cette commande concatène les deux premiers éléments de la pile en un seul élément.

Nous définissons un nombre de sous-charge N comme une chaîne de :et *qui, lorsqu'il est exécuté, consomme l'élément supérieur de la pile et produit N copies de cet élément concaténées ensemble. Quelques exemples:

  • Il n'y a pas de chiffres de sous-charge 0, -1, 1/2, π.
  • La chaîne vide est le chiffre Underload 1, car elle laisse la pile intacte.
  • :*est le nombre de sous-charge 2, car il duplique l'élément supérieur, puis concatène ces deux copies ensemble en un seul élément: (A):*= (A)(A)*= (AA).
  • ::**est le chiffre de sous-charge 3: (A)::**= (A)(A):**= (A)(AA)*= (AAA).
  • :::*** est le chiffre de sous-charge 4.
  • :*:*est également le chiffre de sous-charge 4: (A):*:*= (AA):*= (AA)(AA)*= (AAAA).

En général, vous constaterez que, si Met Nsont les nombres de sous-charge M et N, alors :N*est le chiffre N + 1, et MNest le chiffre M × N.

Le défi

Votre tâche consiste à écrire le programme le plus court (en prenant l'entrée sur STDIN) ou la fonction (en prenant l'entrée via un argument) qui produit la représentation la plus courte du nombre de sous-charge pour son entrée sous forme de chaîne. Autrement dit, si l'entrée est un nombre naturel positif N> 1, vous devez produire un nombre de sous-charge N dont la longueur en caractères est inférieure ou égale à celle de tous les autres nombres de sous-charge N.

Exemples d'entrées et de sorties: ("Input - OUTPUT.")

  • 1 - .
  • 2 - :*.
  • 5 - ::*:**(2 × 2 + 1).
  • 7 - ::*::***(2 × 3 + 1) ou :::**:**(3 × 2 + 1).
  • 33 - ::*:*:*:*:**(2 × 2 × 2 × 2 × 2 + 1).
  • 49 - ::*:*:*:*::***(16 × 3 + 1, longueur 14) mais pas ::*::***::*::***(7 × 7, longueur 16).

Si l'entrée n'est pas un nombre naturel positif, vous êtes libre de renvoyer une erreur, de produire un comportement indéfini ou même de ne pas terminer. Une explication de la méthode de votre soumission pour trouver la réponse est appréciée.

Des restrictions d'échappatoire standard s'appliquent: aucune entrée supplémentaire, aucune demande Web, la valeur de sortie / retour doit être exactement la réponse et non un flux aléatoire infini de :et *, etc.


@Geobits Je n'ai rien dit sur le temps d'exécution, donc tant que vous pouvez prouver qu'il donnera la bonne réponse finalement, vous êtes bon.
algorithmshark

2
Ce problème concerne les chaînes d'addition; en particulier, la longueur de la réponse correcte pour la saisie xest celle 2*A117498(x)A117498 donne la combinaison optimale de méthodes binaires et factorielles pour trouver une chaîne d'addition.
Peter Taylor

Réponses:


4

GolfScript ( 61 60 55 54 53 caractères)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

C'est moins compliqué que ma version précédente et adopte une approche légèrement différente, mais c'est toujours de la force brute. Nous savons que ':'X*'*'X*+c'est une solution candidate, donc si nous générons toutes les chaînes bien équilibrées jusqu'à cette longueur et prenons la plus courte qui évalue à la bonne chose, nous pouvons être certains d'en trouver une.

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

Merci à Howard, de la solution duquel j'ai volé quelques réglages de 1 caractère.


Haha, une entrée de 3 prend plus de trois secondes pour s'exécuter sur l'interpréteur Web. Le golf à son meilleur.
algorithmshark

@algorithmshark, vous pouvez l'accélérer un peu avec un peu de déduplication. Insérer .&juste après la boucle intérieure (c'est-à-dire entre ~}%et }*.
Peter Taylor

4

GolfScript ( 54 53 caractères)

C'est une approche qui est dans l'esprit d'Howard (construire des chaînes qui évaluent à la valeur correcte et sélectionner la plus courte, plutôt que la force brute à travers les chaînes candidates pour trouver celles qui évaluent à la valeur correcte), mais est suffisamment différente pour que je pense il appartient à une réponse séparée.

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

La démonstration en ligne n'est pas disponible car elle exécute une version boguée de l'interpréteur.

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=

Il serait possible d'en raser un en le remplaçant 3+par )(en exploitant le fait qu'il []0=ne reste rien sur la pile) si ce n'était pas le cas, cela []2>entraîne une erreur.
Peter Taylor

[]2>donne []sans erreur.
Howard

@Howard, ah, golfscript.apphb.com doit exécuter une ancienne version. Mais il s'avère que j'avais tort, car ce remplacement conduit à obtenir la mauvaise sortie pour l'entrée '1'.
Peter Taylor

Avec lequel vous pouvez corriger au ((=lieu de -1=.
Howard

Et golfscript.apphb.com exécute en effet une ancienne version, l' exemple des boucles imbriquées ne fonctionne pas.
Howard

4

Python 2.7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

Explication:
il s'agit d'une solution assez simple. Il teste récursivement toutes les représentations possibles de n comme le produit de deux nombres ou comme :(n-1)*, puis trouve la solution de longueur minimale. la plage (2, n) est nécessaire pour que la récursivité ait une profondeur limitée, et n <2 donne le cas de base.

Remarques:
i et n / i sont les deux facteurs de n. Le remplacement ... et ... ou ... de ... si ... sinon ... ne fonctionne pas car '' est évalué comme faux. min de chaînes donne l'une des chaînes les plus courtes. Python 2.7 enregistre 1 caractère en utilisant / au lieu de //.

Edit: Déplacement du cas de base à l'arrière de l'expression, me permettant d'utiliser ... et ... ou ... et de raser quelques espaces.

Cas de test:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'

1
" min of strings donne l'une des chaînes les plus courtes " n'est pas vrai sauf si vous fournissez l'argument facultatif key=len. Il donne la chaîne lexicographiquement la plus ancienne. ( Exemple ). Puisque '*' < ':'cela signifie que vous avez un parti pris pour les solutions impliquant des puissances de 2, mais sont-elles toujours les plus courtes?
Peter Taylor

1
Réponse: en fait, le biais est plus compliqué, mais il ne donne pas toujours la bonne réponse. Le plus petit contre-exemple est u(33), pour lequel le tri lexicographique donne le 14 caractères ::**::*::*:***mais le tri par longueur donne le 12 caractères::*:*:*:*:**
Peter Taylor

1
Je n'ai jamais su cela à propos des comparaisons de chaînes Python. J'ai mis à jour ma réponse.
isaacg

3

GolfScript, 63 58 56 caractères

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

Le code prend l'entrée sur STDIN et imprime le résultat.

Exemples:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

Vous pouvez tester vos propres cas en ligne .


Wow, je pensais qu'une approche basée sur l'affacturage serait un peu plus longue qu'une approche par force brute.
Peter Taylor

@PeterTaylor Je le pensais aussi mais il s'est avéré que ce n'est pas le cas. De plus, ma solution de force brute était un peu plus longue que la vôtre ;-)
Howard

Pourriez-vous expliquer ce que fait chaque portion? Je ne peux que suivre jusqu'au :x(=bout. En outre, +1 pour pouvoir exécuter 49 dans un délai raisonnable.
algorithmshark

@algorithmshark Je travaille toujours sur la solution donc elle pourrait encore changer beaucoup (comme elle vient de le faire). Principalement, la partie x,2>{x\%!},donne tous les vrais diviseurs de x, {.v=x@/v=+}/puis concatène les solutions pour det x/dpour tous les diviseurs d. {,}$les trie par longueur et 0=prend le plus court d'entre eux (plus le :(x-1)*cas initial ).
Howard

2

Brachylog 2 , 30 (peut-être finalement 26) octets, défi de postdates de langue

Voici une fonction qui fonctionne avec l'implémentation actuelle de Brachylog 2 (et retourne une liste de codes de caractères car l'implémentation actuelle a quelques problèmes avec la gestion des chaînes):

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

Essayez-le en ligne!

La langue est encore très nouvelle. Voici une version de 26 octets du programme qui devrait fonctionner selon la spécification, mais utilise des fonctionnalités non implémentées, et n'est donc pas encore valide, mais le sera peut-être à l'avenir (il est également encore moins efficace):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

Explication

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

L'idée de base est assez simple: nous alternons entre décomposer le nombre en (1 ou plusieurs) facteurs (pas nécessairement des facteurs premiers, mais les facteurs de 1 ne sont pas autorisés), et exprimer chacun de ceux-ci comme 1 + (une représentation obtenue à partir d'un récursif appel). Ceci est garanti pour rechercher toutes les représentations de sous-charge possibles du nombre (nous pouvons appliquer une étape de multiplication "deux fois de suite" en multipliant ensemble plus de 2 nombres, et une étape d'incrémentation deux fois de suite en les séparant avec une étape de multiplication qui se multiplie ensemble un seul numéro). Nous n'avons pas besoin d'un cas de base explicite, car la décomposition de 1 en facteurs premiers nous donne une liste vide, et donc nous la construisons avec une étape de multiplication qui multiplie les nombres nuls ensemble.

Le programme est assez inefficace, en particulier parce que le conseil d'ordre d'évaluation que j'ai donné (générer des réponses du plus court au plus long en termes de taille de la sortie éventuelle), tout en résolvant la partie "la plus courte" de la question, n'est pas terrible en termes de en fait, le programme se termine rapidement (un indice beaucoup plus utile serait de «générer uniquement la réponse la plus courte à chaque étape récursive», mais cela prend plus d'octets…). De plus, il ḋp~c×ᵐpeut générer plusieurs fois des partitions multiplicatives, ce qui fait que le programme fait beaucoup de travail redondant.


0

J - 81 car

Pour la postérité, c'était le mieux que je pouvais faire en J.

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

Nous créons une liste de résultats, en commençant par deux chaînes vides (c'est le ,~et a:) représentant 0 (jamais utilisé) et 1, puis nous répétons un verbe dessus (utilisation sournoise de crochets, de trains et &) qui ajoute la représentation la plus courte du numéro suivant.

Le verbe réel que nous itérons utilise la longueur de la liste comme indicateur du nombre sur lequel nous opérons. Tout d'abord, nous factorisons ce nombre en paires de facteurs ( #(#~]-:"1<.)@(],.%)2}.i.@#) et récupérons chaque paire en tirant du tableau ( {~). Nous transformons chacune de ces paires (il pourrait y en avoir 0 si le nombre est premier) en chaînes simples ( <@;"1).

Ensuite, nous ajoutons à cette liste l'entrée pour le résultat précédent entre crochets par :et *, et trions cette liste par longueur ( (/:#&>)). Enfin, nous prenons le premier résultat de cette liste ( 0{) et l'ajoutons à la fin du tableau de base ( [,). Lorsque la boucle est terminée, nous avons une liste de longueur 2 de plus que l'entrée, commençant à 0. Donc, ce que nous devons renvoyer est l'avant-dernière chaîne ( _2{::).

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539

0

Jelly , 33 octets, défi de postdates de langue

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

Essayez-le en ligne!

Une solution simple de force brute.

Explication

Programme principal

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

Le programme principal utilise la fonction d'assistance pour énumérer toutes les manières possibles de produire la valeur par multiplication, puis essaie de produire la valeur par addition et renvoie la possibilité la plus courte. Il gère également le cas de base (une entrée de 1).

Fonction d'assistance

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

La fonction d'assistance essaie toutes les méthodes possibles pour exprimer l'entrée comme une multiplication de deux nombres, et appelle mutuellement récursivement le programme principal afin d'obtenir leurs représentations les plus courtes.


0

GNU Prolog, 96 octets

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

La première ligne est une grammaire qui implémente l'évaluation de la sous-charge et fonctionne dans le sens inverse (en fait, elle ne fonctionne pas tout à fait en raison de la A#<Bcontrainte; changez-la en A#<Npour un programme plus lent qui fonctionne dans les deux sens). La deuxième ligne définit le prédicat de type fonction s(qui est la fonction implémentée comme solution à ce programme) qui trouve la chaîne la plus courte possible qui évalue le nombre donné en entrée (c'est frustrant pour ce qui est une tâche relativement simple, mais c'est Prolog pour vous…).

Le programme devrait être assez explicite, étant donné qu'il s'agit plus ou moins d'une traduction directe de la spécification en grammaire, puis en syntaxe Prolog; la définition de vdit que Nest 1 dans une chaîne vide, ou Nest A× B(avec Amoins de Bmoins que N) et la chaîne est la concaténation de v(A)et v(B), ou Nest signifie "S a une certaine longueur", mais en spécifiant cela comme la première chose sur la La ligne agit comme un indice pour l'implémentation de Prolog qu'elle doit d'abord vérifier les longueurs les plus courtes (ce qui signifie que nous obtiendrons la longueur la plus courte possible pour une valeur de retour).M + 1 et la chaîne est :concaténée avec v(M)concaténée avec *. La deuxième ligne est un peu plus subtile;length(S,_)

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.