Beğendiğiniz sayılarla (neredeyse) denklem çözün


27

+=-En az bir karakterin bulunduğu bir karakter dizisi göz önüne alındığında =, matematiksel denklemlerin yerine getirilmesi için tüm sembollerin arasına ve başında ve sonunda pozitif tam sayılar ekleyin.

Örneğin, giriş verilen

+-=-=

A'dan F'ye pozitif tamsayılar eklemeniz gerekir

A+B-C=D-E=F

bu denklemlerin, ie yerine getirdiğinin A + B - Cve D - Eve Fhepsi aynı sayıda bulunmaktadır.

Bunu yapmanın birçok olası yolu vardır, çünkü denklemler işe yaradığı sürece, herhangi bir pozitif tamsayı kümesi kullanılabilir. Buradaki her satır giriş yapmak için geçerli bir geçerli çıktıdır +-=-=:

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

İfadelerin değerinin, eklenen sayılar gibi pozitif bir tamsayı olması gerekmediğine dikkat edin. Örneğin, belirli bir giriş -=-çıkışları 1-10=8-17(-9 evals) ve 10-1=17-8(9 evals) her ikisi de aynı derecede geçerlidir. Tabii ki bazı girdiler =için ifade olarak negatif olması mümkün değildir, çünkü sadece gibi pozitif sayılar 5=5girilebilir.

Ayrıca, sıfırın pozitif bir tamsayı olmadığını unutmayın.

Bayt cinsinden en kısa kod kazanır.

Sayıları doğrudan dizeye eklemek yerine, bir liste halinde çıktısı alabilirsiniz. Dizeyi çıktılarsanız, sembol ve sayıları ayıran boşluklar olabilir. Yani, giriş için +-=-=, çıkışı

2, 3, 4, 6, 5, 1

veya

2 + 3 - 4 = 6 - 5 = 1

çıktıya eşdeğerdir

2+3-4=6-5=1

Test Kılıfları

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


Formülün uzunluğu üzerinde herhangi bir üst sınır olduğunu varsayabilir miyiz?
xnor

2
@xnor Eğer yardımcı olursa, girişin 2 ^ 16 karakterden kısa olduğunu varsayabilirsiniz.
Calvin'in Hobileri

Yanıtlar:


16

Retina , 58 bayt

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

1+
$.&

Çevrimiçi deneyin!

Aynı bayt sayısında alternatif çözüm:

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

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

Çevrimiçi deneyin!

açıklama

Temel fikir, bütün +s ve s'leri -basit +1ve -1işlemlere dönüştürmek ve ardından tüm denklemlerin çalışmasını sağlayacak kadar büyük bir sayı hazırlamaktır. Denklemlerin eşleşmesini sağlamak için, her birine aynı sayıyı basitçe hazırlayabilir ve ardından her biri için birer birer azaltabilir +1ve her biri için birer birer artırabiliriz -1. Tek sayılarla çalışacağımız için, tek yakalama, ilk sayının, 1 kat azaltabilecek kadar büyük olması gerektiğidir.

[-+]
$&1

1Her birinden sonra -veya ekleyerek başlar +.

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

\BOlmasını sağlar bu maçlar girdi başında ya vardır, ya da bir arasında =bir +veya -yani biz bir ifadenin başına sayı eklemek istediğiniz tüm pozisyonları. ((\+1)|(-1))*Parça daha sonra basitçe sayar +1s ve -1s gruplar halinde 2ve 3sırasıyla. Şimdi değiştirme dizesini parçalayalım:

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

Ardından 1_, ipten gerekli iptali uygulayarak dizgiden düşürün +1.

1+
$.&

Son olarak, 1s'nin tüm dizgilerini uzunluklarından unary'den ondalık karaktere dönüştürmek için uzunlukları ile değiştirin.


8

Python 2,76 bayt

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

Çevrimiçi deneyin!


3
Bir açıklama ekleyebilir misiniz?
Calvin'in Hobileri

1
@HelkaHomba Fikir oldukça basittir: önce girdi bölmesinin her bir parçasını eşit işaretlerle alın. Her öbeğin ilk sayısını seçin eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs. Daha sonra öbek içindeki diğer sayılar da olduğundan, öbek için toplam çalışır eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len. Denklem uzunluğu pozitif olmalı, bu yüzden her şey yolunda.
FryAmTheEggman

6

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

Çok uzun, ama çözümün yaratılması kolaydı.

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

Çevrimiçi deneyin

Bu, bir çözüm bulana kadar her olasılığı deneyecektir. Program son derece yavaştır. Ayrıca, her yinelemede dize değişimini gerçekleştirir. "172" düzenlemesi büyük ölçüde yavaşlattı, çünkü küçük bir aralıktan başlamak yerine maks. Örneğin, girişler -=veya =+2 ** 32 denemek zorunda kaldığınız bir çözüme ulaşmadan önce.

Programı hızlandırmak için, düzenleme geçmişinden 178 bayt olan sürümü kullanın.


rangePython2'de tüm aralığı hemen bir liste yapmaz mı ? IIRC xrangebunun yerine kullanarak hızlandırabilirsiniz , çünkü tembel yükleme sürümü (Python3 varsayılan olarak tembel kullanıyor range)
Delioth

1
@Delioth Ancak, başka bir bayt kullanır. Amaç baytları kaldırmaktır . Ayrıca, yavaşlamanın çoğu, yalnızca bir kez gerçekleşen listenin oluşturulmasından değil, yinelemelerin sayısından kaynaklandığından, bu aslında pek bir hız kazandırmadı. Koştum print range(1,65537)ve 0.034'te tamamlandı.
mbomb007

Tabii ki - daha çok uzun sürdüğü endişesiyle “bu aynı yöntemle onu hızlandırabilir”. Hafızanın parçalanması önemli yavaşlamaya neden olabilir. Ayrıca, bazı baytları (belki sadece 1) ayarlayarak değil l=..., içine yerleştirerek kesebilirsiniz product(range(...),repeat=len(s)+1). Parantez ihtiyacınız varsa, sadece bir bayt (\ n) kaydeder
Delioth

@Delioth Etrafta parenlere ihtiyacım olsa bile len(s)+1, -~len(s)bunun yerine parenler gerektirmeyen bir şey kullanabilirdim .
mbomb007

Ah doğru. Her zaman bitsel işlemleri ve püf noktaları unutuyorum - ön uç javascript Python uzmanlığımı alıyor!
Delioth

5

JavaScript (ES6), 92 82 bayt

@Xnor tarafından bir hile ile 8 bayt golf oynadı

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>

Buradaki hile, 1her birini sonra +veya -sonra her ifadeye ifadeyi girişin uzunluğu eşit yapan sayı hazırlar. Bu şekilde sayının daima pozitif olduğunu garanti edebiliriz; =dizgede her zaman en az 1 olduğundan , +s sayısı dizginin uzunluğuna asla erişemez, bu nedenle kalanlar her zaman en azındandır 1. Bunu, +yukarıdaki snippet'te rasgele bir sayı s yazarak doğrulayabilirsiniz .


5

Python 2 , 120 119 bayt

Mbomb007 sayesinde -1 bayt

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)

Çevrimiçi deneyin! veya Tüm test durumlarını doğrula

Önce 1en yüksek değeri kontrol etmek için her pozisyona yerleştiririm , sonra her denklemde ofset olarak eklerim. Bu iş, çünkü negatif sayılar ekleyemezsiniz, bu yüzden minimum sonuç +sadece sahip olduğu denklemin miktarına göre verilir +.


Birkaç boşluk kaldırabilirsiniz.
mbomb007

5

GNU Prolog, 156 bayt

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

açıklama

Çözmemiz gereken bir sürü denklem var, peki neden gerçek bir denklem çözücü kullanmıyorsunuz?

xtemelde, formun denklemleri için bir denklem değerlendiricisidir +-+; denklemin kendisine ek olarak, iki ek argüman daha vardır ( L,Rdenklemin değerlerini içeren bir fark listesi Vve denklemin değerlendirdiği değer ). Prolog Her zamanki gibi, Belirtebileceğiniz örneğin (herhangi bir şekilde yuvarlak kullanılabilir Vve bir olsun L,R, belirtmek L,Rve bir olsun V, hem belirtmek ve değer doğru olduğundan emin olun, ya da bu durumda, uygun kısıtlamaları hem alınacaktır ne belirtmek Vve L,R). "Geçerli elemanı" L,Rolarak adlandırılır Eve ayrıca şunu da ekleriz:E0'dan büyüktür (çünkü soru pozitif sayıların kullanılmasını gerektirir). Bu işlev istediğimden biraz daha ayrıntılı, örneğin [E|R], listelerin sağ-birleştirici olduğu, ancak toplama ve çıkarmanın sol-birleştirici olduğu için örüntü eşleşmesini / eşleşmesini iki kez yazmam gerekti. Maalesef, çalışmak için kendi sola-ilişkisel liste türümüzü eksiler hücrelerini icat etmek yerine gerçek bir liste kullanmamız gerekiyor fd_labeling.

qbenzer x, ancak aynı zamanda içerir =. Temelde sadece çağırır xve özyinelemeyle. Bu arada, bu farkın listeleri iki farkı listeleri arada kullanabilirsiniz gösteren, nasıl çalıştığını çok net gösteri var L,Tve T,Rtek fark listesine L,R. Temel fikir, bir farklılık listesinin, tartışmayı alan ve listenin kendisine hazır olduğu Rbir değer döndüren kısmi bir işlev olduğu yönündedir. Böylece, bir fark listesinin argümanını ve diğerinin geri dönüş değerini tanımlayarak, fonksiyonları oluşturabilir ve böylece listeleri birleştirebiliriz.LR

Son olarak, ssöz konusu görevi gerçekten çözen funciton, qargümanlarla çağıran bir sarmalayıcı işlevidir . Fark listesini [], argümanı olarak sağlayarak düzenli bir listeye dönüştürüyoruz ve fd_labelingoluşturduğumuz denklem için bir çözüm bulmak için kullanıyoruz . (Varsayılan olarak, değerleri başka bir şeye ayarlamak için bir neden yoksa, değerleri 1 olarak ayarlamak gibi görünür. Ancak, yapılandırılabilir; value_method(random)örneğin her yere 1'leri koymaktan daha "ilginç" çözümler sunar ve hala çok hızlıdır. )

Örnek çıktı

Programda yazılı olarak:

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

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

Programı eklemek için biraz daha uzun yaparsam value_method(random), sonuç değişir, ancak şöyle görünür:

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

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

Her iki durumda da, ?çıktının sonunda, birden fazla çözüm olabileceği anlamına gelir. (Elbette, bu durumda, bir olduğunu biliyorum çok birden fazla çözüm!)


4

Mathematica, 116 bayt

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

Girdi olarak bir dize alarak ve pozitif tamsayıların bir listesini döndüren saf işlev. Temel strateji: biz sadece 1 ekler ve 1 çıkarırız ve herşeyi eşitlemek için her ifadedeki ilk sayıları seçeriz.

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1Her eşittir işaretini giriş dizesi bölmek, ardından her yerine +tarafından -1ve her -tarafından 1. Ancak, başında veya sonunda bir eşittir işareti varsa, göz ardı edilir. Bu nedenle yapay olarak her bir uca ( "0"<>#<>"0") yeni bir karakter ekliyoruz ve dizgenin ayrılması tamamlandıktan sonra ( ) uzaklaşmasını sağlıyoruz /."0"->Nothing.

Artık her bir alt listenin toplamı, her ifadeyi eşitlemek için +s ve -s'nin önüne koyabileceğimiz bir tamsayıya eşittir. 1-Min[Tr/@c]hepsini toplamayı sağlamak için toplamlara ekleyebileceğimiz en küçük tam sayıdır. Böylece Prepend[#^2,1-Min[Tr/@c]+Tr@#]&, her bir alt listeyi alır ( ^2tüm girişlerini 1sıraya getirir ) ve toplamını bu en küçük telafi edici tamsayı ile değiştirir. Elde edilen listeler Joinçıktı üretmek için bir araya getirilir .


3

Ruby, 76

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

İfadelerin hedef değeri 5**8golf nedeniyle eksi 1 olarak belirlendi! Aslında s.size+1eksi 1 kullanıyordum .

Test programında Ungolfed

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["======"]

Çıktı

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 bayt

doğrudan yaklaşım: çok daha kısa ve daha hızlı

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

Çevrimiçi olarak çalıştırın echo '<input>' | php -nR '<code>'veya test edin .

Yıkmak

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"
  • !$cilk yinelemede geçerlidir, 1dizge indekslemesi için kullanılır; "="[1]boş.
    Bundan sonra, $cseti ve bir !$cyalancı, döküm için 0ve "="[0]ilk karakteridir.
  • Herhangi bir terim için maksimum değer, artı +1 sayısını aşmaz;
    bu yüzden girişin uzunluğu konusunda kesinlikle güvendeyiz. Bütün terimler bunu değerlendirecek.
  • chunk_split($s,$n,$i)$iher $nkarakterden sonra $sve sonunda ekler .
    Boş terimlerin dönmesini engellemek için 1, öbek uzunluğunu ayarlayarak bir hata zorlanır 0.

1

Röda , 112 110 109 bayt

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

Çevrimiçi deneyin!

Bölme işlevi bu programda tasarladığım şekilde çalışmadı. Örneğin,split("", sep="") hiçbir şey yerine bir boş dize döndürür. Bu nasıl mantıklı? Bu nedenle, program, ayrık anlambilim ideal olsaydı, olabileceğinden yaklaşık 20 bayttır.

Bu cevabın amacı, giriş dizesinin uzunluğunun denklemin değerine eşit veya daha büyük olması gerektiğini bilmemizdir, bu nedenle denklemin değerini dizginin uzunluğu olarak tanımlarız. Denklemin her bölümü için her operatörün+1 ya da -1çıkardığını ve bunları denklemin değerine eklediğini .

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 ("="). */
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.