Résolvez une équation avec (presque) tous les nombres que vous aimez

27

Étant donné une chaîne de caractères +=-où il y en a au moins un =, insérez des entiers positifs entre tous les symboles et au début et à la fin de sorte que les équations mathématiques soient satisfaites.

Par exemple, étant donné l'entrée

+-=-=

vous devez insérer des entiers positifs A à F comme celui-ci

A+B-C=D-E=F

de telle sorte que les équations sont toutes satisfaites, c'est A + B - C-à- dire et D - Eet Fsont toutes le même nombre.

Il existe de nombreuses façons de le faire puisque, tant que les équations fonctionnent, tout ensemble d'entiers positifs peut être utilisé. Chaque ligne ici est une sortie valide possible à saisir +-=-=:

2+3-4=6-5=1
1+1-1=2-1=1
4+2-4=4-2=2
100+1-10=182-91=91
89+231-77=1024-781=243

Notez que la valeur des expressions n'est pas obligatoirement un entier positif comme le sont les nombres insérés. Par exemple, pour une entrée donnée, -=-les sorties 1-10=8-17(Evals à -9) et 10-1=17-8(Evals à 9) sont toutes deux également valables. Bien sûr, pour certaines entrées comme =il est impossible d'avoir un négatif comme expression car seuls des nombres positifs comme 5=5peuvent être insérés.

Notez également que zéro n'est pas un entier positif.

Le code le plus court en octets gagne.

Vous pouvez afficher les nombres sous forme de liste au lieu de les insérer directement dans la chaîne. Si vous sortez la chaîne, il peut y avoir des espaces séparant les symboles et les nombres. Donc, pour l'entrée +-=-=, la sortie

2, 3, 4, 6, 5, 1

ou

2 + 3 - 4 = 6 - 5 = 1

équivaut à la sortie

2+3-4=6-5=1

Cas de test

Input | One Possible Output
= | 1=1
== | 2=2=2
+= | 1+3=4
=+ | 2=1+1
-= | 30-10=20
=- | 1=2-1
=-= | 3=7-4=3
=+= | 2=1+1=2
=== | 100=100=100=100
+=- | 3+2=7-2
-=+ | 7-2=3+2
+=+ | 3+3=3+3
-=- | 1-10=8-17
--= | 60-1-1=58
++= | 60+1+1=62
-+= | 60-9+1=52
+-= | 60+9-1=68
+-=-= | 2+3-4=6-5=1
--=-- | 2-1-1=2-1-1
==-== | 47=47=50-3=47=47
=++=+-=-+=--= | 3=1+1+1=3+1-1=1-1+3=5-1-1=3
+--++-=-+-+- | 35+10-16-29+20+107-1000=5-4+3-2+1-876
====== | 8=8=8=8=8=8=8
Loisirs de Calvin
la source
En relation.
Martin Ender
Pouvons-nous supposer une limite supérieure sur la longueur de la formule?
xnor
2
@xnor Vous pouvez supposer que l'entrée comporte moins de 2 ^ 16 caractères si cela vous aide.
Calvin's Hobbies

Réponses:

16

Rétine , 58 octets

[-+]
$&1
\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&
+`1_

1+
$.&

Essayez-le en ligne!

Solution alternative au même nombre d'octets:

((\+)|(-))*
$._$*1$#3$*1$#2$*_$&
+`1_

([+-])1*
$+1
1+
$.&

Essayez-le en ligne!

Explication

L'idée de base est de transformer tous les +s et -s en simples +1et des -1opérations, puis à préfixer un assez grand nombre qui fait tout le travail des équations. Pour faire correspondre les équations, nous pouvons simplement ajouter le même nombre à chacun d'eux, puis le réduire d'un pour chacun +1et l'augmenter d'un pour chacun -1après. Puisque nous travaillerons avec des nombres unaires, le seul problème est que le premier nombre doit être suffisamment grand pour que nous puissions le réduire de 1 fois suffisamment.

[-+]
$&1

Nous commençons par insérer un 1après chaque -ou +.

\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&

Le \Bs'assure que ces correspondances sont soit au début de l'entrée, soit entre a =et a +ou -, c'est-à-dire toutes les positions où l'on veut insérer le numéro de tête d'une expression. La ((\+1)|(-1))*partie compte alors simplement le nombre de +1s et de -1s dans les groupes 2et 3respectivement. Maintenant, décomposons la chaîne de substitution:

$._$*1   # For each character in the current string, insert a 1. This is
         # an offset which is the same for each expression and is guaranteed
         # to be large enough that all subsequent +1s can be cancelled.
$#3$*1   # For each -1, insert a 1.
$#2$*_   # For each +1, insert a _.
$&       # Re-insert the string of +1s and -1s.
+`1_

Supprimez à plusieurs reprises 1_de la chaîne, en appliquant l'annulation requise de l' +1art.

1+
$.&

Enfin, remplacez toutes les chaînes de 1s par leurs longueurs pour convertir de unaire en décimal.

Martin Ender
la source
8

Python 2 , 76 octets

lambda e:sum([[len(e+s)-2*s.count('+')]+[1]*len(s)for s in e.split('=')],[])

Essayez-le en ligne!

xnor
la source
3
Pouvez-vous ajouter une explication?
Calvin's Hobbies
1
@HelkaHomba L'idée est assez simple: prenez d'abord chaque morceau de l'entrée divisé par des signes égaux. Choisissez le premier numéro de chaque morceau eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs. Puis, comme tous les autres nombres du bloc sont des nombres, le total du bloc est égal à eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len. La longueur de l'équation doit être positive, donc tout fonctionne.
FryAmTheEggman
6

Python 2, 199 179 178 172 162 158 156 152 151 octets

Beaucoup trop long, mais la solution était facile à créer.

from itertools import*
i=input()
k='%s'
s=k+k.join(i)+k
for p in product(*[range(1,65537)]*-~len(i)):
    if eval((s%p).replace('=','==')):print s%p;break

Essayez-le en ligne

Cela tentera toutes les possibilités jusqu'à ce qu'il trouve une solution. Le programme est extrêmement lent. Il effectue également le remplacement de chaîne à chaque itération. L'édition "172" l'a rendu considérablement plus lent, car plutôt que de commencer par une petite plage, il commence au maximum. Par exemple, les entrées -=ou =+doivent essayer 2 ** 32 tentatives avant d'arriver à une solution.

Pour accélérer le programme, utilisez la version avec 178 octets de l'historique des modifications.

mbomb007
la source
rangeEn python2, ne crée- t-il pas immédiatement toute la plage sous forme de liste? IIRC vous pouvez accélérer en utilisant à la xrangeplace, car je pense que c'est la version à chargement paresseux (Python3 utilise paresseux par défaut range)
Delioth
1
@Delioth Cela utilise cependant un autre octet. Le but est de supprimer les octets. De plus, cela n'apporterait pas beaucoup d'accélération, car la majorité du ralentissement provient du nombre d'itérations, pas de la création de la liste, qui ne se produit qu'une seule fois. J'ai couru print range(1,65537)et cela s'est terminé en 0,034 s.
mbomb007
Eh bien, bien sûr - plus d'un "cela pourrait accélérer avec exactement la même méthodologie", sur le souci de prendre si longtemps. Le débordement de mémoire peut entraîner un ralentissement important. En outre, vous pouvez réduire certains octets (peut-être seulement 1) en ne définissant pas l=..., mais en mettant cela dans le product(range(...),repeat=len(s)+1). Si vous avez besoin de parenthèses, il
n'enregistre
@Delioth Même si j'avais besoin de parens len(s)+1, je pourrais utiliser à la -~len(s)place, ce qui ne nécessiterait pas de parens.
mbomb007
Ah, c'est vrai. J'oublie toujours les opérations et les trucs au niveau du bit - ce doit être le tribut de travailler sur le frontend javascript prend mon expertise Python!
Delioth
5

JavaScript (ES6), 92 82 octets

Golfé 8 octets avec un tour de @xnor

let f =
x=>x.split`=`.map(q=>(x+q).length-2*~-q.split`+`.length+[...q,''].join(1)).join`=`
<input oninput="if(/^[+=-]+$/.test(value))O.innerHTML=f(value)" value="="><br>
<pre id=O>1=1</pre>

L'astuce consiste à insérer un 1après chaque +ou -, puis à ajouter à chaque expression le nombre qui rend l'expression égale à la longueur de l'entrée. De cette façon, nous pouvons garantir que le nombre est toujours positif; comme il y a toujours au moins 1 =dans la chaîne, le nombre de +s ne peut jamais atteindre la longueur de la chaîne, donc le reste est toujours au moins 1. Vous pouvez le vérifier en tapant un nombre arbitraire de +s dans l'extrait ci-dessus.

ETHproductions
la source
5

Python 2 , 120 119 octets

-1 octet grâce à mbomb007

a=['1'+(n and('1'.join(n)+'1'))for n in input().split('=')]
print'='.join(`max(map(eval,a))-eval(c)+1`+c[1:]for c in a)

Essayez-le en ligne! ou vérifier tous les cas de test

D'abord, j'insère 1dans chaque position, pour vérifier la valeur la plus élevée, puis je l'ajoute comme décalage sur chaque équation. Cela fonctionne parce que vous ne pouvez pas ajouter de nombres négatifs, donc le résultat minimum est donné par le montant de +l'équation qui n'a que +.

Barre
la source
Vous pouvez supprimer quelques espaces.
mbomb007
5

GNU Prolog, 156 octets

x(L,R,V)-->{E#>0},({L=[E|R],E=V};x(L,[E|R],X),("+",{V#=X+E};"-",{V#=X-E})).
q(L,R,V)-->x(L,T,V),({T=R};"=",q(T,R,V)).
s(Q,L):-q(L,[],_,Q,[]),fd_labeling(L).

Explication

Nous avons un tas d'équations à résoudre, alors pourquoi ne pas utiliser un véritable solveur d'équations?

xest essentiellement un évaluateur d'équations pour les équations de la forme +-+; en plus de l'équation elle-même, elle a deux arguments supplémentaires (une liste de différences L,Rqui contient les valeurs de l'équation et une valeur à Vlaquelle l'équation évalue). Comme d'habitude dans Prolog, il peut être utilisé dans tous les sens (par exemple, vous pouvez spécifier Vet obtenir un L,R, spécifier L,Ret obtenir un V, spécifier les deux et vérifier que la valeur est correcte, ou spécifier ni l'un ni l'autre dans ce cas, les contraintes appropriées seront placées sur les deux Vet L,R). "L'élément actuel" de L,Rest nommé E, et nous incluons également une affirmation selon laquelleEest supérieur à 0 (car la question nécessite l'utilisation de nombres positifs). Cette fonction est légèrement plus détaillée que je ne le souhaiterais, par exemple j'ai dû écrire le [E|R]motif match / unmatch deux fois, car les listes sont associatives à droite mais l'addition et la soustraction sont associatives à gauche. Malheureusement, nous devons utiliser une liste réelle, plutôt que d'inventer notre propre type de liste associative de gauche à partir de cellules par contre, pour fd_labelingfonctionner.

qest similaire à x, mais comprend également =. Il appelle simplement xet récursivement. Soit dit en passant, c'est une démonstration très claire du fonctionnement des listes de différences, montrant que vous pouvez concaténer deux listes de différences L,Tet T,Ren une seule liste de différences L,R. L'idée de base est qu'une liste de différences est une fonction partielle qui prend un argument Ret retourne une valeur Lqui lui est ajoutée Rpar la liste elle-même. Ainsi, en identifiant l'argument d'une liste de différences et la valeur de retour d'une autre, nous pouvons composer les fonctions, et donc concaténer les listes.

Enfin, squi est la fonction qui résout réellement la tâche dans la question, est une fonction wrapper qui appelle qavec des arguments. Nous convertissons la liste des différences en une liste régulière en fournissant []comme argument et utilisons fd_labelingpour trouver une solution à l'équation que nous avons construite. (Par défaut, il semble aimer définir des valeurs à 1 s'il n'y a aucune raison de les définir sur autre chose. Cependant, il peut être configuré; value_method(random)donne des solutions plus "intéressantes" que de mettre des 1 partout, par exemple, et est toujours très rapide. )

Exemple de sortie

Avec le programme tel qu'écrit:

| ?- s("=++=+-=-+=--=", V).

V = [3,1,1,1,3,1,1,3,1,1,5,1,1,3] ?

Si je rallonge le programme pour en ajouter un value_method(random), le résultat varie, mais ressemble à ceci:

| ?- s("=++=+-=-+=--=", V).

V = [68,6,12,50,85,114,131,45,3,26,71,1,2,68] ? 

Dans les deux cas, la ?fin de la sortie signifie qu'il peut y avoir plus d'une solution. (Bien sûr, dans ce cas, nous savons qu'il existe bien plus d'une solution!)


la source
4

Mathematica, 116 octets

Join@@(Prepend[#^2,1-Min[Tr/@c]+Tr@#]&/@(c=Characters@StringSplit["0"<>#<>"0","="]/."+"->-1/."-"->1/."0"->Nothing))&

Fonction pure prenant une chaîne en entrée et renvoyant une liste d'entiers positifs. Stratégie de base: nous ajoutons toujours 1 et soustrayons 1, et nous choisissons les nombres initiaux dans chaque expression pour que tout soit égal.

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1diviserait la chaîne d'entrée à chaque signe égal, puis remplacerait chaque +par -1et chaque -par 1. Cependant, s'il y a un signe égal au début ou à la fin, il serait ignoré. Par conséquent, nous ajoutons artificiellement un nouveau caractère à chaque extrémité ( "0"<>#<>"0") et le faisons disparaître une fois le fractionnement de chaîne terminé ( /."0"->Nothing).

Le total de chaque sous-liste est maintenant égal à un entier que nous pouvons mettre devant le +s et le -s pour rendre chaque expression égale. 1-Min[Tr/@c]est le plus petit entier que nous pouvons ajouter à chaque total pour les rendre tous positifs. Prepend[#^2,1-Min[Tr/@c]+Tr@#]&Prend donc chaque sous-liste (les ^2transforme toutes leurs entrées 1) et ajoute son total décalé par ce plus petit entier compensateur. Les listes résultantes sont Joinéditées ensemble pour produire la sortie.

Greg Martin
la source
3

Rubis, 76

->s{(?1+s.gsub(/./){|a|a+?1}).split(?=).map{|e|e[0]="#{5**8-eval(e)}";e}*?=}

La valeur cible des expressions est fixée à 5**8moins 1 pour des raisons de golf! À l'origine, j'utilisais s.size+1moins 1.

Non testé dans le programme de test

f=->s{(?1+s.gsub(/./){|a|a+?1}).           #add a 1 at the beginning and after every symbol
       split(?=).                          #split into an array of expressions at = signs
       map{|e|                             #for each expression string
         e[0]="#{5**8-eval(e)}";e          #change the first number to 5**8-eval(e)
       }*?=                                #and rejoin the strings
}


puts f["="] 
puts f["=="] 
puts f["+="] 
puts f["=+"]
puts f["-="]
puts f["=-"]
puts f["=-="]
puts f["=+="]
puts f["==="]
puts f["+=-"]
puts f["-=+"]
puts f["+=+"]
puts f["-=-"]
puts f["--="]
puts f["++="]
puts f["-+="]
puts f["+-="]
puts f["+-=-="]
puts f["--=--"]
puts f["==-=="]
puts f["=++=+-=-+=--="]
puts f["+--++-=-+-+-"]
puts f["======"]

Sortie

390624=390624
390624=390624=390624
390623+1=390624
390624=390623+1
390625-1=390624
390624=390625-1
390624=390625-1=390624
390624=390623+1=390624
390624=390624=390624=390624
390623+1=390625-1
390625-1=390623+1
390623+1=390623+1
390625-1=390625-1
390626-1-1=390624
390622+1+1=390624
390624-1+1=390624
390624+1-1=390624
390624+1-1=390625-1=390624
390626-1-1=390626-1-1
390624=390624=390625-1=390624=390624
390624=390622+1+1=390624+1-1=390624-1+1=390626-1-1=390624
390624+1-1-1+1+1-1=390625-1+1-1+1-1
390624=390624=390624=390624=390624=390624=390624
Level River St
la source
2

PHP, 207 204 197 114 octets

approche directe: beaucoup plus courte et plus rapide

foreach(explode("=",$argn)as$t)echo"="[!$c],strlen($argn)+($c=count_chars($t))[45]-$c[43],@chunk_split($t,!!$t,1);

Exécutez-le echo '<input>' | php -nR '<code>'ou testez-le en ligne .

panne

foreach(explode("=",$argn)as$t) // loop through terms
    echo                            // print ...
        "="[!$c],                       // 1. "=" if not first term
        strlen($argn)                   // 2. maximum number
            +($c=count_chars($t))[45]   //    + number of "-"
            -$c[43],                    //    - number of "+"
        @chunk_split($t,!!$t,1);        // 3. each operator followed by "1"
  • !$cest vrai dans la première itération, transtypé en 1pour l'indexation des chaînes; "="[1]est vide.
    Après cela, $cest défini et !$cfaux, transtypé en 0et "="[0]est le premier caractère.
  • La valeur maximale pour un terme quelconque ne doit pas dépasser le nombre de plus +1;
    donc nous sommes définitivement en sécurité avec la longueur de l'entrée. Tous les termes seront évalués à cela.
  • chunk_split($s,$n,$i)insère $iaprès chaque $ncaractère de $s- et à la fin.
    Pour éviter que les termes vides ne se transforment en 1, une erreur est forcée en définissant la longueur du bloc sur 0.
Titus
la source
1

Roda , 112 110 109 octets

f x{[(`:$x:`/"=")()|{|p|p~=":",""a=p;a~=`\+`,""b=p;b~="-","";["=",#x-#b+#a];{(p/"")|{|o|[o,"1"*#o]}_}}_][1:]}

Essayez-le en ligne!

La fonction de division n'a pas fonctionné comme je l'avais prévu avec ce programme. Par exemple, split("", sep="")renvoie une chaîne vide au lieu de rien. Comment est-ce logique? Pour cette raison, le programme est près de 20 octets plus grand que ce qu'il pourrait être si la sémantique divisée était idéale.

L'idée de cette réponse est que nous savons que la longueur de la chaîne d'entrée doit être supérieure ou égale à la valeur de l'équation, nous définissons donc la valeur de l'équation comme étant la longueur de la chaîne. Pour chaque partie de l'équation, nous pensons que chaque opérateur étant +1ou -1et soustrayons et les ajoutons à la valeur de l'équation.

Non golfé:

function f(x) {
    /* Adds ":"s around the string to prevent "=" being split wrong. */
    [split(`:$x:`, sep="=") | for p do
        p ~= ":", ""          /* Removes colons. */
        a := p; b := p        /* Initializes a and b to be p. */
        a ~= "\\+", ""        /* The lengths of a and are now equal to the */
        b ~= "-", ""          /* numbers of "-" and "+" characters in x. */
        push("=", #x-#b+#a)   /* Prints "=" and the value of the equation */
                              /* minus number of "+"s plus number of "-"s. */
        split(p, sep="") | for o do /* For each operator: */
            push(o)                 /* Prints the operator. */
            push(1) if [o != ""]    /* Prints 1 unless the operator is "". */
        done
    done][1:] /* Removes the first character of the output ("="). */
}
fergusq
la source