Risolvi un'equazione con (quasi) tutti i numeri che ti piacciono


27

Data una stringa di caratteri in +=-cui ce n'è almeno uno =, inserisci numeri interi positivi tra tutti i simboli e all'inizio e alla fine in modo tale che le equazioni matematiche siano soddisfatte.

Ad esempio, dato l'input

+-=-=

devi inserire numeri interi positivi da A a F in questo modo

A+B-C=D-E=F

tale che le equazioni siano tutte soddisfatte, cioè A + B - Ce D - Ee Fabbiano tutti lo stesso numero.

Esistono molti modi possibili per farlo poiché, fintanto che le equazioni si risolvono, è possibile utilizzare qualsiasi set di numeri interi positivi. Ogni riga qui è un possibile output valido da inserire +-=-=:

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

Si noti che il valore delle espressioni non deve essere un numero intero positivo come lo sono i numeri inseriti. Ad esempio, dato l'ingresso, -=-le uscite 1-10=8-17(valutazione da -9) e 10-1=17-8(valutazione da 9) sono entrambe ugualmente valide. Naturalmente per alcuni input come =è impossibile avere un negativo come espressione, poiché è 5=5possibile inserire solo numeri positivi come .

Si noti inoltre che zero non è un numero intero positivo.

Vince il codice più breve in byte.

È possibile generare i numeri come elenco invece di inserirli direttamente nella stringa. Se si genera la stringa, potrebbero esserci spazi che separano simboli e numeri. Quindi, per input +-=-=, output

2, 3, 4, 6, 5, 1

o

2 + 3 - 4 = 6 - 5 = 1

equivale a produrre

2+3-4=6-5=1

Casi 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


Possiamo assumere un limite superiore per la lunghezza della formula?
xnor

2
@xnor È possibile supporre che l'input sia lungo meno di 2 ^ 16 caratteri se ciò aiuta.
Calvin's Hobbies

Risposte:


16

Retina , 58 byte

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

1+
$.&

Provalo online!

Soluzione alternativa con lo stesso numero di byte:

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

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

Provalo online!

Spiegazione

L'idea di base è trasformare tutte le +s -in semplici +1e -1operazioni e quindi anteporre un numero sufficientemente grande che faccia funzionare tutte le equazioni. Per far corrispondere le equazioni, possiamo semplicemente anteporre lo stesso numero a ciascuno di essi, quindi ridurlo di uno per ciascuno +1e aumentarlo di uno per ciascuno -1dopo di esso. Dal momento che lavoreremo con numeri unari, l'unico problema è che il primo numero deve essere abbastanza grande da poterlo ridurre di 1 abbastanza volte.

[-+]
$&1

Iniziamo inserendo un 1dopo ciascuno -o +.

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

Le \Bgarantisce che queste partite sono o all'inizio di ingresso, o tra un =e una +o -, cioè tutte le posizioni in cui si desidera inserire il numero iniziale di un'espressione. La ((\+1)|(-1))*parte poi semplicemente conta il numero di +1s e -1s in gruppi 2e 3, rispettivamente. Ora suddividiamo la stringa di sostituzione:

$._$*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_

Caduta ripetutamente 1_dalla stringa, applicando la cancellazione richiesta dalla +1s.

1+
$.&

Infine, sostituisci tutte le stringhe di 1s con le loro lunghezze per convertire da unario a decimale.


8

Python 2 , 76 byte

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

Provalo online!


3
Puoi aggiungere una spiegazione?
Hobby di Calvin

1
@HelkaHomba L'idea è abbastanza semplice: prima prendi ogni blocco dell'input diviso per segni uguali. Scegli il primo numero di ogni pezzo da essere eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs. Quindi, poiché tutti gli altri numeri nel blocco sono quelli, il totale per il blocco si risolve eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len. La lunghezza dell'equazione deve essere positiva, quindi tutto funziona.
FryAmTheEggman

6

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

Troppo a lungo, ma la soluzione è stata facile da creare.

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

Provalo online

Questo proverà ogni possibilità fino a quando non troverà una soluzione. Il programma è estremamente lento. Esegue anche la sostituzione della stringa ogni iterazione. La modifica "172" l'ha resa drasticamente più lenta, poiché anziché iniziare con un intervallo ridotto inizia al massimo. Ad esempio, gli input -=o =+devono provare 2 ** 32 tentativi prima di raggiungere una soluzione.

Per accelerare il programma, utilizzare la versione con 178 byte dalla cronologia delle modifiche.


Non rangein python2 creare tutta la gamma come una lista subito? IIRC potresti accelerarlo usando xrangeinvece, poiché penso che sia la versione a caricamento lento (Python3 usa lazy come predefinito range)
Delioth

1
@Delioth Che utilizza un altro byte, però. L'obiettivo è rimuovere i byte. Inoltre, ciò non fornirebbe molta accelerazione, poiché la maggior parte del rallentamento è dovuta al numero di iterazioni, non alla creazione dell'elenco, che si verifica solo una volta. Ho corso print range(1,65537)e completato in 0,034 s.
mbomb007

Beh, certo- più di un "questo potrebbe accelerarlo esattamente con la stessa metodologia", con la preoccupazione che ci impieghi così tanto tempo. Il thrashing della memoria potrebbe causare un significativo rallentamento. Inoltre, potresti tagliare alcuni byte (forse solo 1) non impostandoli l=..., ma inserendoli nel product(range(...),repeat=len(s)+1). Se hai bisogno di parentesi, salva solo un byte (\ n)
Delioth

@Delioth Anche se avessi bisogno delle parentesi in giro len(s)+1, potrei usare -~len(s)invece, che non richiederebbe le parentesi.
mbomb007

Ah giusto. Dimentico sempre le operazioni e i trucchi bit per bit: deve essere il pedaggio che il frontend javascript sta assumendo sulla mia esperienza in Python!
Delioth,

5

JavaScript (ES6), 92 82 byte

Giocato a golf 8 byte con un trucco di @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>

Il trucco qui è inserire un 1dopo ogni +o -, quindi anteporre a ogni espressione il numero che rende l'espressione uguale alla lunghezza dell'input. In questo modo possiamo garantire che il numero sia sempre positivo; poiché =nella stringa è sempre presente almeno 1 , il numero di +s non può mai raggiungere la lunghezza della stringa, quindi il resto è sempre almeno 1. Puoi verificarlo digitando un numero arbitrario di +s nel frammento sopra.


5

Python 2 , 120 119 byte

-1 byte grazie a 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)

Provalo online! oppure Verifica tutti i casi di test

Prima inserisco 1in ogni posizione, per controllare il valore più alto, quindi lo aggiungo come offset su ogni equazione. Questo funziona perché non puoi aggiungere numeri negativi, quindi il risultato minimo è dato dalla quantità di +nell'equazione che hanno solo +.


Puoi rimuovere un paio di spazi.
mbomb007

5

GNU Prolog, 156 byte

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).

Spiegazione

Abbiamo un sacco di equazioni da risolvere, quindi perché non usare un vero risolutore di equazioni?

xè fondamentalmente un valutatore di equazioni per equazioni del modulo +-+; oltre all'equazione stessa, ha due argomenti aggiuntivi (un elenco delle differenze L,Rche contiene i valori dell'equazione e un valore a Vcui l'equazione valuta). Come al solito in Prolog, può essere utilizzato in qualsiasi modo (ad esempio, è possibile specificare Ve ottenere un L,R, specificare L,Re ottenere un V, specificare entrambi e verificare che il valore sia corretto, oppure specificare in entrambi i casi che verranno applicati vincoli appropriati su entrambi Ve L,R). L '"elemento corrente" di L,Rè chiamato E, e includiamo anche un'affermazione cheEè maggiore di 0 (perché la domanda richiede l'uso di numeri positivi). Questa funzione è leggermente più dettagliata di quanto mi piacerebbe, ad esempio ho dovuto scrivere il [E|R]modello match / unmatch due volte, a causa del fatto che gli elenchi sono associativi a destra ma l'addizione e la sottrazione sono associative a sinistra. Purtroppo, abbiamo bisogno di usare un elenco reale, piuttosto che inventare il nostro tipo di elenco associativo di sinistra dalle celle contro, per fd_labelingfunzionare.

qè simile a x, ma include anche =. Praticamente chiama xe ricorsivamente. Per inciso, è una dimostrazione molto chiara di come funzionano gli elenchi di differenze, dimostrando che è possibile concatenare due elenchi di differenze L,Te T,Rin un unico elenco di differenze L,R. L'idea di base è che un elenco di differenze è una funzione parziale che accetta un argomento Re restituisce un valore Lche è Rcon l'elenco stesso ad esso anteposto. Pertanto, identificando l'argomento di un elenco di differenze e il valore restituito di un altro, possiamo comporre le funzioni e quindi concatenare gli elenchi.

Infine, sche è la funzione che risolve effettivamente l'attività nella domanda, è una funzione wrapper che chiama qcon argomenti. Convertiamo l'elenco delle differenze in un elenco regolare fornendo []come argomento, e usiamo fd_labelingper trovare una soluzione all'equazione che abbiamo costruito. (Per impostazione predefinita, sembra voler impostare i valori su 1 se non c'è motivo di impostarli su qualcos'altro. Tuttavia, può essere configurato; value_method(random)offre soluzioni più "interessanti" rispetto al mettere 1 in tutto il mondo, ad esempio, ed è ancora molto veloce. )

Uscita campione

Con il programma come scritto:

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

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

Se aggiungo un po 'più tempo al programma per aggiungere un value_method(random), il risultato varia, ma assomiglia a questo:

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

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

In entrambi i casi, ?alla fine dell'output significa che potrebbe esserci più di una soluzione. (Certo, in questo caso, sappiamo che c'è molto più di una soluzione!)


4

Mathematica, 116 byte

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

Funzione pura che accetta una stringa come input e restituisce un elenco di numeri interi positivi. Strategia di base: aggiungiamo sempre solo 1 e sottraggiamo 1 e scegliamo i numeri iniziali in ciascuna espressione per rendere tutto uguale.

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1sarebbe dividere la stringa di input ad ogni segno di uguale, quindi sostituire ogni +da -1e ciascuno -per 1. Tuttavia, se c'è un segno di uguale all'inizio o alla fine, verrebbe ignorato. Pertanto aggiungiamo artificialmente un nuovo carattere a ciascuna estremità ( "0"<>#<>"0") e lo facciamo scomparire dopo che la divisione della stringa è stata completata ( /."0"->Nothing).

Il totale di ciascun sottoelenco ora corrisponde ad un numero intero che possiamo mettere davanti alle +s e -S per rendere ogni espressione uguale. 1-Min[Tr/@c]è il numero intero più piccolo che possiamo aggiungere a ciascun totale per renderli tutti positivi. Quindi Prepend[#^2,1-Min[Tr/@c]+Tr@#]&prende ogni sublist ( ^2trasforma tutte le loro voci in 1) e antepone il suo totale spostato da questo intero compensatore più piccolo. Gli elenchi risultanti vengono Joineditati insieme per produrre l'output.


3

Ruby, 76

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

Il valore target per le espressioni è fissato a 5**8meno 1 per motivi di golf! Inizialmente stavo usando s.size+1meno 1.

Non registrato nel programma di 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["======"]

Produzione

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

2

PHP, 207 204 197 114 byte

approccio diretto: molto più breve e più veloce

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

Esegui echo '<input>' | php -nR '<code>'o prova online .

abbattersi

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"
  • !$cè vero nella prima iterazione, cast 1per l'indicizzazione delle stringhe; "="[1]è vuoto.
    Dopodiché, $cè impostato e !$cfalso, lanciato su 0ed "="[0]è il primo personaggio.
  • Il valore massimo per qualsiasi termine non deve superare il numero di plus +1;
    quindi siamo sicuramente al sicuro con la lunghezza dell'input. Tutti i termini lo valuteranno.
  • chunk_split($s,$n,$i)inserisce $idopo ogni $ncarattere di $s- e alla fine.
    Per evitare che termini vuoti si trasformino in 1, un errore viene forzato impostando la lunghezza del blocco su 0.

1

Röda , 112 110 109 byte

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

Provalo online!

La funzione split non ha funzionato come previsto con questo programma. Ad esempio, split("", sep="")restituisce una stringa vuota anziché nulla. Com'è logico? Per questo motivo il programma ha una dimensione di quasi 20 byte maggiore di quello che potrebbe essere se la semantica divisa fosse l'ideale.

L'idea di questa risposta è che sappiamo che la lunghezza della stringa di input deve essere maggiore o uguale al valore dell'equazione, quindi definiamo il valore dell'equazione come la lunghezza della stringa. Per ogni parte dell'equazione, pensiamo che ogni operatore sia +1o -1e sottrae e li aggiungiamo al valore dell'equazione.

Ungolfed:

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 ("="). */
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.