(ほぼ)任意の数値で方程式を解く


27

+=-少なくとも1つの文字の文字列が与えられた=場合、数学方程式が満たされるように、すべてのシンボル間および開始と終了に正の整数を挿入します。

たとえば、与えられた入力

+-=-=

このように正の整数AからFを挿入する必要があります

A+B-C=D-E=F

式はすべて、すなわち、満たされていることなどA + B - CD - Eし、Fすべて同じ番号です。

方程式が機能する限り、正の整数のセットを使用できるため、これを行うには多くの方法があります。ここの各行は、入力に対して可能な有効な出力です+-=-=

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

式の値は、挿入された数値のように正の整数である必要はないことに注意してください。たとえば、入力-=-が与えられた場合、出力1-10=8-17(-9の値)と10-1=17-8(9の値)は両方とも等しく有効です。もちろん、入力のよう=な正の数値のみを5=5挿入できるため、式として負の値を持つことは不可能です。

また、ゼロは正の整数ではないことに注意してください。

バイト単位の最短コードが優先されます。

数値を文字列に直接挿入する代わりに、リストとして出力することもできます。文字列を出力する場合、記号と数字を区切るスペースがあります。したがって、入力+-=-=、出力

2, 3, 4, 6, 5, 1

または

2 + 3 - 4 = 6 - 5 = 1

出力と同等です

2+3-4=6-5=1

テストケース

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


数式の長さの上限を想定できますか?
-xnor

2
@xnor入力が2 ^ 16文字未満であると仮定することができます。
カルバンの趣味

回答:


16

網膜、58バイト

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

1+
$.&

オンラインでお試しください!

同じバイト数での代替ソリューション:

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

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

オンラインでお試しください!

説明

基本的な考え方は、すべて有効にすることです+sおよび-シンプルにSを+1して-1操作して、すべての方程式の作業を行い十分な数を付加します。方程式を一致させるには、それぞれに同じ数を追加し、それを1つずつ減らし、その後で1ずつ+1増やし-1ます。単項の数値を使用するため、唯一の問題は、最初の数値が十分に大きくなければならないということです。

[-+]
$&1

1-orの後にa を挿入することから始め+ます。

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

\Bこれらの一致は入力の冒頭に、または間のいずれかであることを保証=し、+または-、すなわち我々は表現の主要な番号を挿入したいすべての位置。 ((\+1)|(-1))*一部では、単に数をカウント+1sおよび-1sのグループ内2および3それぞれ。次に、置換文字列を分解します。

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

1_から必要なキャンセルを適用して、文字列から繰り返しドロップします+1

1+
$.&

最後に、1sのすべての文字列をその長さに置き換えて、単項から10進数に変換します。


8

Python 2、76バイト

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

オンラインでお試しください!


3
説明を追加できますか?
カルバンの趣味

1
@HelkaHombaアイデアは非常に単純です。まず、入力の各チャンクを等号で分割します。各チャンクの最初の番号を選択しますeqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs。チャンク内の他のすべての数値は1であるため、チャンクの合計はになりeqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_lenます。方程式の長さは正でなければならないため、すべてがうまくいきます。
FryAmTheEggman

6

パイソン2、199 179 178 172 162 158の 156 152 151バイト

長すぎますが、ソリューションの作成は簡単でした。

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

オンラインで試す

これにより、解決策が見つかるまであらゆる可能性が試されます。プログラムは非常に遅いです。また、繰り返しごとに文字列の置換を実行します。「172」編集により、範囲が狭い範囲から始まるのではなく、最大値から始まるため、大幅に遅くなりました。たとえば、入力する-==+、ソリューションに到達する前に2 ** 32回試行する必要があります。

プログラムを高速化するには、編集履歴から178バイトのバージョンを使用します。


rangepython2では、範囲全体をすぐにリストとして作成しませんか?IIRCはxrange、代わりに使用することで速度を上げることができます。これは遅延読み込みバージョンだと思います(Python3は遅延としてデフォルトを使用しますrange
Delioth

1
@Deliothただし、別のバイトを使用します。目標はバイトを削除することです。また、スローダウンの大部分は繰り返しの数によるものであり、リストの作成は1回だけであるため、実際にはそれほど高速化されません。私は走りprint range(1,65537)、0.034秒で完了しました。
mbomb007

まあ、もちろん、「これはまったく同じ方法論でそれをスピードアップすることができます」ということです。メモリのスラッシングにより、大幅な速度低下が発生する可能性があります。また、を設定せずににl=...入れることで、いくつかのバイト(おそらく1)をカットできますproduct(range(...),repeat=len(s)+1)。括弧が必要な場合は、1バイト(\ n)しか保存されません
-Delioth

@Delioth周りlen(s)+1に括弧が必要な場合でも、-~len(s)代わりに使用できます。これは括弧を必要としません。
mbomb007

ああ、そう。私は常にビット単位の操作とトリックを忘れています-フロントエンドjavascriptがPythonの専門知識を引き継いでいるのは間違いないでしょう!
-Delioth

5

JavaScript(ES6)、92 82バイト

@xnorからのトリックで8バイトをゴルフ

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>

ここでのコツは1、すべての+orまたはの後にaを挿入し-、その後、式を入力の長さと等しくする番号を各式の先頭に追加することです。このようにして、数が常に正であることを保証できます。=文字列には常に少なくとも1つあるため、+s の数が文字列の長さに達することはないため、残りは常に少なくとも1です。これを確認するに+は、上記のスニペットに任意の数のsを入力します。


5

パイソン2120の 119バイト

mbomb007のおかげで-1バイト

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)

オンラインでお試しください!またはすべてのテストケースを検証する

最初に1すべての位置に挿入し、最高値を確認してから、すべての方程式のオフセットとして追加します。負の数を追加できないため、これは機能します。したがって、最小の結果は+、のみを持つ方程式の量によって与えられます+


いくつかのスペースを削除できます。
mbomb007

5

GNU Prolog、156バイト

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

説明

解くべき方程式がたくさんあるので、実際の方程式ソルバーを使用してみませんか?

xは基本的に次の形式の方程式の方程式評価器です+-+。方程式自体に加えて、2つの追加の引数(L,R方程式の値を含む差分リスト、およびV方程式が評価する値)があります。プロローグではいつものように、それはあなたが指定することができますどのような方法ラウンド(例えば使用することができますVし、取得しL,R、指定L,RしてもらうV、その場合には、適切な制約は、両方の上に置かれませんどちらも両方を指定し、値が正しいことを確認、または指定をVし、L,R)。の「現在の要素」のL,R名前Eはです。また、E0よりも大きい(質問では正数を使用する必要があるため)。[E|R]リストは右結合ですが、加算と減算は左結合であるという事実のために、この関数は私が望むよりも少し冗長です。悲しいことに、コンスセルから独自の左結合リストタイプを作成するのではなく、実際のリストを使用する必要がありますfd_labeling

qはに似てxいますが、も含まれてい=ます。基本的にを呼び出しx、それ自体を再帰的に呼び出します。ちなみに、それはあなたが2差のリストを連結することができることを示して、差分リストがどのように動作するかの非常に明確なデモンストレーションだL,TT,R、単一の差分リストにL,R。基本的な考え方は、差分リストは引数を取り、リスト自体が先頭に付加されRた値Lを返す部分関数であるというRことです。したがって、1つの差分リストの引数と別のリストの戻り値を識別することにより、関数を構成し、リストを連結できます。

最後にs、問題のタスクを実際に解決する関数である、はq引数付きで呼び出すラッパー関数です。[]引数として指定することにより、差分リストを通常のリストに変換し、作成したfd_labeling方程式の解を見つけるために使用します。(デフォルトでは、他の値を設定する理由がない場合、値を1に設定するように見えます。ただし、設定することもできます。value_method(random)たとえば、どこにでも1を置くよりも「興味深い」ソリューションを提供します。 )

サンプル出力

書かれたプログラムで:

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

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

プログラムを少し長くしてaを追加するvalue_method(random)と、結果は異なりますが、次のようになります。

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

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

どちらの場合でも、?出力の最後は、複数のソリューションが存在する可能性があることを意味します。(もちろん、この場合には、我々はそこだということを知っている多くの複数の解決策!)


4

Mathematica、116バイト

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

入力として文字列を取り、正の整数のリストを返す純粋な関数。基本的な戦略:1を加算して1を減算するだけで、すべての式が等しくなるように各式の初期数を選択します。

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1入力文字列をすべての等号で分割し、各+by -1とeach -byを置き換えます1。ただし、先頭または末尾に等号がある場合は無視されます。そのため、各"0"<>#<>"0"文字列に人為的に新しい文字を追加し()、文字列の分割が完了した後に文字を削除します(/."0"->Nothing)。

各サブリストの合計は整数に等しくなり、+sおよび-sの前に置いて各式を等しくすることができます。1-Min[Tr/@c]は、合計をすべて正にするために各合計に追加できる最小の整数です。したがってPrepend[#^2,1-Min[Tr/@c]+Tr@#]&、各サブリストを取得し(^2すべてのエントリをに1変換します)、この最小の補正整数でシフトされた合計を先頭に追加します。結果のリストはJoinまとめて出力されます。


3

ルビー、76

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

式の目標値は、5**8ゴルフの理由でマイナス1に固定されています!もともと私はs.size+1マイナス1 を使用していました。

テストプログラムでゴルフをしていない

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

出力

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バイト

直接的なアプローチ:はるかに短くて速い

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

オンラインで実行するecho '<input>' | php -nR '<code>'、オンラインでテストします

壊す

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"
  • !$c1文字列のインデックス付けのためにキャストされる最初の反復ではtrue です。"="[1]空です。
    その後、$cが設定されて!$cfalseに0なり"="[0]、最初の文字にキャストされます。
  • 任意の用語の最大値は、プラス+1の数を超える必要はありません。
    そのため、入力の長さは間違いなく安全です。すべての条件がそれに評価されます。
  • chunk_split($s,$n,$i)-の$iすべての$n文字の後$sおよび末尾に挿入します。
    空の用語がに変わるのを防ぐために1、チャンクの長さをに設定することでエラーが強制されます0

1

ローダ112の 110 109バイト

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

オンラインでお試しください!

このプログラムで意図したとおり、分割機能は機能しませんでした。たとえばsplit("", sep="")、何もではなく1つの空の文字列を返します。それは論理的ですか?このため、プログラムは分割セマンティクスが理想的な場合よりも20バイト近く大きくなります。

この答えのアイデアは、入力文字列の長さが方程式の値以上でなければならないことを知っているため、方程式の値を文字列の長さと定義することです。方程式のすべての部分について、すべての演算子が+1orである-1と考え、それらを減算して方程式の値に加算します。

ゴルフをしていない:

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 ("="). */
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.