Expression égale à sa longueur


14

Étant donné un nombre, trouvez une expression dans les mots égale à ce nombre, avec une longueur de ce nombre.

Ainsi, sur une entrée de 15, vous pouvez générer une sortie sixteen minus onequi comporte quinze caractères (sans compter les espaces). S'il existe plusieurs solutions, imprimez celle que vous souhaitez. S'il n'en existe pas, imprimezimpossible

Utilisez uniquement les opérateurs plus, minus, timeset divided by. Les opérateurs sont évalués de gauche à droite.

Format 1234 as one thousand two hundred thirty four. Notez l'absence de "et", et qu'il n'y a pas de tirets ou de virgules.

L'entrée et tous les nombres utilisés dans la sortie doivent être des entiers positifs inférieurs à 10 000.

L'entrée sera donnée comme argument de ligne de commande. Imprimez sur la sortie standard.

Exemples

1: impossible
4: four
7: impossible
13: eight plus five (you could also output "five plus eight")
18: one plus two times six (note that operators are evaluated from left to right)
25: one thousand divided by forty

4
entiers non négatifs? So for 1234 we can do (massive expression) times zero plus one thousand two hundred thirty four.Vous souhaiterez peut-être exclure zéro. Dépend de vous.
Level River St

@steveverrill Bon point; Je l'ai changé en "entiers positifs".
Ypnypn

4
sooo ... one hundred three times one times one times one times one times one times one times one times one times one times one times oneest valide?
Qwix

@Qwix Oui; des réponses ennuyeuses sont acceptables, bien que celle-ci ne fonctionne pas pour 104, 105, 106, 107, 108, 109, 110 ou 111.
Ypnypn

Réponses:


1

Javascript, 434 caractères

function f(s){return s.replace(/[A-Z]/g,function(t){return{O:'one',T:'two',H:'three',F:'four',I:'five',S:'six',E:'seven',G:'eight',N:'nine',Z:'ten',P:' plus ',M:' minus ',U:' times ',X:'teen',A:'thir',B:'twenty'}[t]})}A='TPAX|GeenMT|EXUO|B FMS|F|GPSUT|ZPHPG|BPFMT|AXPFPS|BPGMF|EUOPGeen|NPT|B GMSPI|GPI|EPE'.split('|');O=26640;function S(n){return n<15&&!(O>>n&1)?'Invalid':f(A[v=n%15])+(new Array(~~(n/15)+(O>>v&1))).join(f('PSPN'))}

Donne une fonction dans l'espace de noms global,, Squi accepte tout entier non négatif et renvoie la chaîne requise, ou "Invalid"si l'entier ne peut pas être représenté dans les spécifications.

Il semblerait que j'aie utilisé la même approche que @optokopper, ayant fait la même observation qui "plus six plus nine"est la chaîne de remplissage la plus courte possible, et que tous les nombres supérieurs à 27 peuvent être exprimés en concaténant l'une des 15 chaînes de base à des copies répétées du tampon.

Cela dit, les tables de chaînes de base que nous utilisons diffèrent, et ma solution repose sur le twiddling de bits et l'opérateur restant ( %). Il comprend également "multiplied by"une opération possible. Et naturellement, la mécanique de construction des chaînes est complètement différente en raison de la dissemblance entre C et Javascript.

C'est ma meilleure tentative, en tout cas. ;)

Un merci spécial à @chiru, dont la discussion sur les chiffres réalisables a permis d'éviter les recherches infructueuses.


22

JS, 1719/1694

Théorie

Malheureusement, l'ensemble de règles que vous fournissez n'est peut-être pas une sage décision d'un point de vue mathématique. En fait, en utilisant un plus petit sous-ensemble de règles, vous pouvez trouver une solution pour chaque nombre dans l'intervalle donné

I = [1;  10000]

à l'exception de

X = [1;  3] ∪ [5;  10] ∪ {12}

pour lequel il n'y a pas de solution.

Jeu de règles réduit

Considérez le sous-ensemble de règles suivant:

  • Utilisez uniquement les opérateurs plus, minuset times.
  • Vous n'avez pas besoin d'implémenter plusieurs occurrences de plusou minusdans vos expressions.
  • Vous n'avez pas besoin d'implémenter ni divisionni operator associativity(car leur ensemble de solutions est déjà couvert par la première règle).

La raison pour laquelle cela fonctionne est que, comme vous l'avez expliqué précédemment avec @Qwix, vous autorisez des réponses ennuyeuses , c'est-à-dire des expressions qui se terminent par l'expression régulière ( times one)+$. En permettant cela, chaque nombre dans l'intervalle donné aura une solution.

Lorsque vous avez répondu dans l'un de vos commentaires,

@Qwix Oui; des réponses ennuyeuses sont acceptables, bien que celle-ci ne fonctionne pas pour 104, 105, 106, 107, 108, 109, 110 ou 111. -

vous aviez absolument raison: cela ne fonctionne pas lorsque vous essayez de construire votre expression en commençant par les nombres eux-mêmes, c'est-à-dire one hundred four times one times one …ou tout autre de ces nombres.

Si toutefois, votre expression commence par une expression dont l'évaluation est égale à l'un des nombres donnés, vous n'avez pas de chance. Par exemple, notez que 17 + 87c'est effectivement le cas 104, donc nous pourrions écrire 104comme:

104: seventeen plus eighty seven times one times one times one times one times one times one times one times one times one times one

Pour voir que ce sous-ensemble fonctionne, enregistrez ce fichier sous num.jset assurez-vous que SpiderMonkey, un moteur JavaScript pour les lignes de commande, est installé sur votre système.

L'algorithme

  • Définissons la propriété Kdes entiers positifs comme l'état du nombre ayant des Nlettres et ayant une valeur de N.
  • Définissons en outre la propriété Fd'une expression comme l'état de sa conversion de mots étant 8k-temps plus court que son évaluation avec k ∈ ℕ. Fsignifie "fillable" et décrit si nous pouvons ou non remplir la conversion de mots de l'expression avec des expressions de longueur 8 (c'est-à-dire " times one") de telle sorte que l'expression résultante puisse obtenir la propriété N.

Nous procédons ensuite comme suit:

  • Convertissez le nombre saisi en mots.
  • Vérifiez si le numéro saisi a une propriété K.
    • Si c'est le cas, renvoyez les mots ( 4c'est le seul numéro avec cette propriété, malheureusement).
    • Si ce n'est pas le cas, continuez.
  • Pour toutes les expressions à deux opérandes (additions, soustractions et multiplications dans cet ordre) qui aboutissent au numéro d'entrée, vérifiez si leur évaluation a une propriété K.
    • Si c'est le cas, renvoyez les mots.
    • Si ce n'est pas le cas, vérifiez si l'expression à deux opérandes a une propriété N.
      • Si c'est le cas, remplissez l'expression avec " times one"et vérifiez si l'évaluation de l'expression résultante a une propriété K.
        • Si c'est le cas, renvoyez les mots
        • Si ce n'est pas le cas, continuez
      • Si ce n'est pas le cas, continuez
  • Va boire un café

Entraine toi

num.js (pour SpiderMonkey / lignes de commande)

function X(e,t){return e+": "+t}function P(e){var n,t;for(n=1;.5*e+(e%2===0?1:0)>n;++n){if(t=C.s(n)+" plus "+C.s(e-n),t.replace(/\s/g,"").length===e)return t;if(F(e,t)&&e>t.length)return G(e,t)}return!1}function M(e){var t,n;for(t=L;t>1;--t){if(0>t-e)return!1;if(n=C.s(t)+" minus "+C.s(t-e),n.replace(/\s/g,"").length===e)return n;if(F(e,n)&&e>n.length)return G(e,n)}return!1}function F(e,t){return(e-t.replace(/\s/g,"").length)%8===0}function G(r,t){var e,i=(r-t.replace(/\s/g,"").length)/8,n="";for(e=0;i>e;++e)n+=" times one";return t+n}function T(e){var t,n,r;if(F(e,C.s(e)))return G(e,C.s(e));for(t=1,n=1;t<Math.floor(Math.sqrt(e));++t){for(;e>tn;)++n;if(tn===e&&(r=C.s(t)+" times "+C.s(n),r.replace(/\s/g,"").length===e))return r}return!1}function Y(e){var n,r,t;return e===C.s(e).length?X(e,C.s(e)):(n=P(e))?X(e,n):(r=M(e))?X(e,r):(t=T(e),t?X(e,t):X(e,"impossible"))}var L=1e4,C=new function(){return this.o=["","one","two","three","four","five","six","seven","eight","nine"],this.t=["","","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"],this.T=["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"],this.s=function(e){return e?this.m(e):"zero"},this.m=function(e){return e>=1e6?this.m(Math.floor(e/1e6))+" million"+(e%1e6!==0?" "+this.Z(e%1e6):""):this.Z(e)},this.Z=function(e){return e>=1e3?this.h(Math.floor(e/1e3))+" thousand"+(e%1e3!==0?" "+this.h(e%1e3):""):this.h(e)},this.h=function(e){return e>99?this.o[Math.floor(e/100)]+" hundred"+(e%100!==0?" "+this.U(e%100):""):this.U(e)},this.U=function(e){return 10>e?this.o[e]:e>=10&&20>e?this.T[e-10]:this.t[Math.floor(e/10)]+(e%10!==0?" "+this.o[e%10]:"")},this};print(Y(0|arguments[0]))

num.js (pour les navigateurs)

Le code donné ci-dessus ne peut pas fonctionner pour les navigateurs en raison de sa dernière commande, qui saisit les arguments de la ligne de commande afin de faire une belle commande à partir du script donné.

Afin d'exécuter le code JavaScript directement à partir de votre navigateur, sélectionnez cette partie du code ci-dessus:

function X(e,t){return e+": "+t}function P(e){var n,t;for(n=1;.5*e+(e%2===0?1:0)>n;++n){if(t=C.s(n)+" plus "+C.s(e-n),t.replace(/\s/g,"").length===e)return t;if(F(e,t)&&e>t.length)return G(e,t)}return!1}function M(e){var t,n;for(t=L;t>1;--t){if(0>t-e)return!1;if(n=C.s(t)+" minus "+C.s(t-e),n.replace(/\s/g,"").length===e)return n;if(F(e,n)&&e>n.length)return G(e,n)}return!1}function F(e,t){return(e-t.replace(/\s/g,"").length)%8===0}function G(r,t){var e,i=(r-t.replace(/\s/g,"").length)/8,n="";for(e=0;i>e;++e)n+=" times one";return t+n}function T(e){var t,n,r;if(F(e,C.s(e)))return G(e,C.s(e));for(t=1,n=1;t<Math.floor(Math.sqrt(e));++t){for(;e>tn;)++n;if(tn===e&&(r=C.s(t)+" times "+C.s(n),r.replace(/\s/g,"").length===e))return r}return!1}function Y(e){var n,r,t;return e===C.s(e).length?X(e,C.s(e)):(n=P(e))?X(e,n):(r=M(e))?X(e,r):(t=T(e),t?X(e,t):X(e,"impossible"))}var L=1e4,C=new function(){return this.o=["","one","two","three","four","five","six","seven","eight","nine"],this.t=["","","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"],this.T=["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"],this.s=function(e){return e?this.m(e):"zero"},this.m=function(e){return e>=1e6?this.m(Math.floor(e/1e6))+" million"+(e%1e6!==0?" "+this.Z(e%1e6):""):this.Z(e)},this.Z=function(e){return e>=1e3?this.h(Math.floor(e/1e3))+" thousand"+(e%1e3!==0?" "+this.h(e%1e3):""):this.h(e)},this.h=function(e){return e>99?this.o[Math.floor(e/100)]+" hundred"+(e%100!==0?" "+this.U(e%100):""):this.U(e)},this.U=function(e){return 10>e?this.o[e]:e>=10&&20>e?this.T[e-10]:this.t[Math.floor(e/10)]+(e%10!==0?" "+this.o[e%10]:"")},this}

Maintenant, collez-le dans la console JavaScript de votre navigateur, afin de pouvoir produire les mêmes résultats à partir de votre navigateur avec, par exemple:

Y(1234);

Exemples (ligne de commande)

chiru@chiru ~ $ js num.js 28
28: fourteen plus fourteen times one
chiru@chiru ~ $ js num.js 7
7: impossible
chiru@chiru ~ $ js num.js 42
42: nine thousand sixty minus nine thousand eighteen

Et pour voir l'astuce avec laquelle vous pouvez faire fonctionner chaque numéro, jetez un œil à la réponse ennuyeuse pour js num.js 1337:

1337: ten plus one thousand three hundred twenty seven times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one

Les codes fournis génèrent des solutions valides pour l'intervalle donné (et probablement même au-dessus, vous n'auriez qu'à augmenter la valeur de la variable L).

Statistiques

Je m'intéressais à "l' ennui " des expressions (ou: à quel point la sous-chaîne times oneétait utilisée par expression dans cet algorithme), car cette partie était chargée de trouver une solution pour chaque nombre dans l'intervalle donné. Voyez par vous-même:

x : n-ième expression (min. 0, max. 10 000)

y : nombre d'occurrences de la sous-chaîne "fois un" dans l'expression (min. 0, max. 1245)

Graphique

Conclusions:

  • Les expressions ont tendance à devenir de plus en plus ennuyeuses de manière linéaire.
  • Plus de 99% des solutions sont ennuyeuses.

2
Une solution pour 4 existefour
FUZxxl

@FUZxxl Je n'ai jamais nié cela. Si vous répondez If it does, return the words (4 is the only number with this property, unfortunately), vous avez peut-être mal compris cette section. Il dit que 4c'est la seule expression sans opérateur qui forme sa propre solution.
Chiru

@FUZxxl Oh, d'accord. Je viens de remarquer que dans la section de début, j'ai dit qu'il n'y avait pas de solutions dans X = [0; 10] ∪ {12}, bien que plus tard, je dis que cela 4a une solution. J'ai corrigé l'intervalle, merci. :)
Chiru

6

C, 450 caractères

Modifier: supprimé zero

Modifier: utiliser uniquement plusetminus

J'ai recherché l'expression la plus courte qui ajoute des caractères et maintient la condition vraie. J'ai trouvé plus ten plus fiveest long de 15 et ajoute 15 à la chaîne.

Je n'ai besoin que d'expressions pour les 15 premiers nombres qui ne sont pas impossibles, pour exprimer n'importe quel nombre possible. 12 est le plus grand nombre impossible, il suffit donc de coder en dur des nombres plus petits 28.

4 = quatre
11 = six plus cinq
13 = huit plus cinq
14 = vingt moins six
15 = vingt moins cinq
16 = dix-huit moins deux
17 = quatorze plus trois
18 = vingt-deux moins quatre
20 = trente-deux moins douze
21 = vingt plus deux moins un
22 = vingt plus quatre moins deux
23 = trente moins huit plus un
24 = vingt plus huit moins quatre
25 = vingt plus huit moins trois
27 = vingt-huit moins six plus cinq

Nous pouvons écrire chaque nombre> 27 comme x * 15 + un des nombres ci-dessus.

Golfé

#define P" plus "
#define M" minus "
#define U"four"
#define F"five"
#define E"eight"
#define W"twenty"
#define A"ten"P F P
*e[]={0,0,0,0,U,0,0,0,0,0,0,F P"six",0,E P F,W M"six",W M F,E"een"M"two",U"teen"P"three",W" two"M U,A U,"thirty two"M"twelve",W P"two"M"one",W M"two"P U,"thirty"P"one"M E,W P E M U,W M"three"P E,A F P"six",W" "E M"six"P F};main(n){n=atoi(1[(int*)1[&n]]);for(printf("%d: ",n);n>27;n-=15)printf(A);puts(e[n]?e[n]:"impossible");}

Code lisible

#include <stdio.h>
#include <stdlib.h>

// add fifteen to string, both as value and as character count (without spaces)
const char *add_fifteen = "plus ten plus five";

// table with hardcoded expressions
// NOTE: we could calculate 19, 26, 28 and 29 from 4, 11, 13 and 14
// but we would need more logic, so we hardcode those 4 numbers too.
const char *expressions[30]={"impossible", "impossible", "impossible", "impossible",
    "four", "impossible", "impossible", "impossible", "impossible",
    "impossible", "impossible", "five plus six", "impossible",
    "eight plus five", "twenty minus six",
    "fourteen plus one", "eighteen minus two", "fourteen plus three",
    "twenty two minus four", "four plus ten plus five",
    "thirty two minus twelve", "nine plus seven plus five",
    "twenty plus four minus two", "twelve plus seven plus four",
    "twenty plus eight minus four", "twenty plus eight minus three",
    "five plus six plus ten plus five", "twenty eight minus six plus five",
    "eight plus five plus ten plus five", "seven plus seven plus ten plus five"};

int main(int argc,char *argv[])
{
    int n = strtol(argv[1], NULL, 0);
    int fifteens = 0;

    printf("%d: ", n);

    // how many times do we need to add fifteen?
    if(n>29){
        fifteens=(n/15) - 1;
        n -= fifteens*15; // ensure 30 > n >= 15, so we don't get "impossible"
    }

    // look up the expression for n
    printf("%s", expressions[n]);

    // add fifteens till we are done
    while(fifteens-- > 0) {
        printf(" %s", add_fifteen);
    }

    printf("\n");
    return 0;
}

2
Vous ne savez pas exactement comment fonctionne votre code, mais comme la question l'indique all numbers used in the output must be positive integers, pourriez-vous supprimer le #define Z "zero"de votre code ainsi que les instances de Z car vous ne devriez jamais l'utiliser?
Qwix

"plus douze" est de 12 lettres. Est-ce que cela aiderait à raccourcir votre code?
isaacg

Je le raccourcirais, hélas les espaces ne comptent pas, plus twelvec'est seulement 10 lettres
Optokopper

OK, j'ai mal lu les règles.
isaacg
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.