j=Integer;f=Flatten;s=SequenceReplace;A=FixedPoint[f@s[#,{{x_j,p,y_j,t}->{y,t,x*y,p},{x_j,y_j,p}->x+y,{x_j,y_j,t}->x*y,{x_j,p,y_j,p}->{x+y,p},{x_j,t,y_j,t}->{x*y,t},{0,p}|{1,t}->{},{0,t}->{d,0}}]//.{a___,Except[i|o]}->{a}&,#]&;B=Expand@Check[f@FoldPairList[f/@Switch[#2,i,{{i},{#,i@c++}},o,{{Last@#},#},d,{{},Most@#},p,{{},{#[[;;-3]],Tr@#[[-2;;]]}},t,{{},{#[[;;-3]],#[[-2]]*Last@#}},_,{{},{##}}]&,c=0;{},#],x]&;F=MinimalBy[w=A@f[#/.m->{-1,t,p}];z=B@w;s[#,{-1,t,p}->m]&/@A/@Select[Permutations@Join[w,Cases[z /.i@_->i,_j,∞]],B@#==z&],Length][[1]]&
オンラインでお試しください!
これは4段階のツアーデフォースであり、(1)「-」を「-1 * +」に置き換えます。これにより、減算を処理する必要がなくなります。(2)コマンドのリストを少し簡略化します( 3)コマンドのこのリストのすべての順列のリストを作成し、解析(実行)したときに同じ結果をもたらすものを選択します。(4)コマンドのこれらのリストを少し単純化し、特定の操作を引き算。
このコードは、入力コードのすべての順列のリストを通過するため、非常に非効率的です。長い入力コードの場合、このコードを実行することはお勧めしません。しかし、私がそれを読んだとき、このチャレンジにはランタイムやメモリの制限はありません。
このコードは、符号を反転してすべての「-」操作を「+」操作に変換した後に最適化ステップを実行し、最後にコードを文字列に戻すときに「-」演算子を再導入します。これは、たとえば「i -1 i * + o」が「ii-o」に正しく最適化されることを意味します。
I / O形式の要件は非常に緩いため、このコードはコードをリストとして受け取り、シンボル「+」、「-」、「*」がそれぞれp、m、t、トークンで表されます。文字列との間の変換は、TIOで指定されたラッパー関数で行われます。
G[S_] := StringReplace[{"p" -> "+", "m" -> "-", "t" -> "*"}]@StringRiffle@
Quiet@F@
ToExpression[StringSplit[S] /. {"+" -> p, "-" -> m, "*" -> t}]
文字列形式のラッパーを含み、トークンの数ではなく最終的なコード文字列の長さを最小化し、さらにいくつかの変換機能を含む、ゴルフのないバージョン:
(* convert code string to list of operators *)
inputfilter[s_] := ToExpression[Flatten[StringSplit[s] /.
{"i" -> i, "o" -> o, "d" -> d, "+" -> p, "-" -> {-1, t, p}, "*" -> t}]]
(* convert list of operators to code string *)
outputfilter[s_] := StringReplace[StringRiffle@Flatten@SequenceReplace[s,
{{-1, t, p} -> m, (* convert "-1 t p" back to "-" *)
{x_ /; x < 0, p} -> {-x, m}, (* convert "y x +" to "y -x -" when x<0 *)
{x_ /; x < 0, t, p} -> {-x, t, m}}], (* convert "y x * +" to "y -x * -" when x<0 *)
{"m" -> "-", "p" -> "+", "t" -> "*"}] (* backsubstitution of symbols *)
(* simplify a list of operators somewhat *)
simplifier[s_] := FixedPoint[Flatten@SequenceReplace[#,
{{x_Integer, p, y_Integer, t} -> {y, t, x*y, p}, (* "x + y *" -> "y * (xy) +" *)
{x_Integer, y_Integer, p} -> x + y, (* "x y +" -> "(x+y)" *)
{x_Integer, y_Integer, t} -> x*y, (* "x y *" -> "(xy)" *)
{x_Integer, p, y_Integer, p} -> {x + y, p}, (* "x + y +" -> "(x+y) +" *)
{x_Integer, t, y_Integer, t} -> {x*y, t}, (* "x * y *" -> "(xy) * *)
{0, p} | {1, t} -> {}, (* "0 +" and "1 *" are deleted *)
{x_Integer, i, p} -> {i, x, p}, (* "x i +" -> "i x +" *)
{x_Integer, i, t} -> {i, x, t}, (* "x i *" -> "i x *" *)
{0, t} -> {d, 0}}] //. (* "0 *" -> "d 0" *)
{a___, Except[i | o]} -> {a} &, s] (* delete trailing useless code *)
(* execute a list of operators and return the list of generated outputs *)
parse[s_] := Expand@Quiet@Check[Flatten@FoldPairList[ (* stack faults are caught here *)
Function[{stack, command}, (* function called for every command*)
Flatten /@ Switch[command, (* code interpretation: *)
i, {{i}, {stack, i[inputcounter++]}}, (* output "i" and add input to stack*)
o, {{stack[[-1]]}, stack}, (* output top of stack *)
d, {{}, Most[stack]}, (* delete top of stack *)
p, {{}, {stack[[;; -3]], stack[[-2]] + stack[[-1]]}}, (* add two stack elements *)
t, {{}, {stack[[;; -3]], stack[[-2]]*stack[[-1]]}}, (* multiply two stack elements*)
_, {{}, {stack, command}}]], (* put number onto stack *)
inputcounter = 0; {}, (* start with zero input counter and empty stack*)
s], (* loop over code list *)
x] (* return "x" if an error occurred *)
(* the main function that takes a code string and returns an optimized code string *)
F[s_] := Module[{w, q},
w = simplifier@inputfilter@s; (* convert input to useful form *)
q = parse[w]; (* execute input code *)
MinimalBy[
outputfilter@*simplifier /@ (* simplify and stringify selected codes *)
Select[Permutations[w], (* all permutations of code list *)
parse[#] == q &], (* select only those that give the correct output *)
StringLength] // Union] (* pick shortest solution by length *)
バグをキャッチしてくれた@redundancyに感謝します:パーサーはExpand
、出力の等価性を処理するために出力に適用する必要があります。506→513
更新
また、に最適化1 o 1 + o
し1 o 2 o
ます。これは驚くほど難しいケースであり、コードの速度が大幅に低下しました。513→548
i i d o
にi o i
(入力が順序であり、出力は順序である)、またはあなたはそれを簡略化するべきではないのですか?(入力と出力のセットは順番になっている必要があります)