海野秀之(うんのひでゆき)の外部記憶
Twitter (twilog) / RSS / アンテナ / ぶくま
このところ Google の検索結果にでなくなってしまっている 「水からの伝言」を信じないでください の冒頭に、以下のような文が追加されていた。
11 月 11 日前後から、このページが Google の検索にかからなくなっています。 これは、最近頻出している Google の技術的トラブルの可能性が高いとの ご指摘をご専門の方からいただきました。 要は、Google に頼りすぎてはいけないということでしょうね (11月14日)。
そういえば、最上嗣生さんがGoogle に ad-hoc なアルゴリズムを導入することで不安定になると言っていた のを思いだした。
(蛇足) 私は google の試行錯誤的なシステムが改変がいけないことだとは思っていません。 さっきの局所最適解と次の局所最適解の間は不安定でしょうから。 (←しまった、最上さんの主張をまったく理解していないように見えるなぁ。)
似たような出題を二回目撃してしまったため、 スルー力(するー・りょく)及ばず、変なフラグが立ってしまった。
いずれも 24 をターゲットにしているのは、切符問題にはなにか僕の知らない流儀でも?? さらに、解いてみると(と書くとさくっと解いたように聞こえるかも知れませんが、恥ずかしながら、 そんなことはありません *1) 、いずれの答えも同じ形の構文木になります。
むむー、この形が人間にとっては思いつきにくいということかな。
まだお二人のコードをきちんと読んでいませんが、 おそらく、それらとくらべて断然素人臭いと思われますが、拙作を以下に (ticket.rb)。
いやね、There is more than one way to do it が言い訳モットーでして。
次は scheme で書いてみよう。Shiro Kawai さんのコードを詳しくしらべるのはそれから。 (ざっと見た感じ、あんなコードは僕からは出てきそうにもない。非決定性なんちゃらって何だ? *2 )
#!/usr/local/bin/ruby =begin ticket.rb いわゆる切符問題をときます。 「1, 3, 4, 6 の 4 つの数字(順序は入れ替えてよい)と四則演算をもちいて 24 をつくれ」 だったら、 ./ticket.rb 24 1 3 4 6 になります。 =end require 'rational' =begin == each_tree_permutaion(array) {|a| ... } 配列をうけとって、構文木の候補を生成します。 たとえば、[a, b, c] からは [[a, b], c], [[b, a], c], [c, [a, b]], ... が次々に生成されブロックに渡されます。 =end def each_tree_permutation(ary) pr = Proc.new if ary.size > 2 0.upto(ary.size - 1) do |i0| a = ary.dup x = a.delete_at(i0) 0.upto(a.size - 1) do |i1| b = a.dup y = b.delete_at(i1) 0.upto(b.size) do |j| each_tree_permutation(b.dup.insert(j, [x, y]), &pr) end end end else pr.call(ary) end end =begin == each_operations(ary){|a| ... } each_tree_permutation で生成された木の各ノード [x, y] に 可能な四則演算をはめこんでブロックに渡します。 [x, y] は、['+', x, y], ['-', x, y], ['*', x, y], ['/', x, y] になります。y が 0 でないか等の検査はしない。 (eval まかせ) =end OPS=['+', '-', '*', '/'] def each_operations(ary) x,y, = ary def unexpanded?(a) a.class == Array and a.size != 3 end if unexpanded? x each_operations(x) do |a| if unexpanded? y each_operations(y) do |b| OPS.each do |op| yield([op, a, b]) end end else OPS.each do |op| yield([op, a, y]) end end end else if unexpanded? y each_operations(y) do |b| OPS.each do |op| yield([op, x, b]) end end else OPS.each do |op| yield([op, x, y]) end end end end =begin == eval(expr) => [value, string] each_operation が返す形式を受け取って、 値を評価します。 評価値と式の表現(文字列)の組を返します。 =end def eval(expr) op, x, y, = expr def v_and_s(a) if a.class == Array eval(a) else [a, a.to_s] end end x_val, x_str = v_and_s(x) y_val, y_str = v_and_s(y) ret_val = nil if x_val and y_val case(op) when '+' ret_val = x_val + y_val when '-' ret_val = x_val - y_val when '*' ret_val = x_val * y_val when '/' if y_val != 0 ret_val = x_val / y_val else ret_val = nil end end end ret_str = "(#{x_str} #{op} #{y_str})" [ret_val, ret_str] end # ======== main ======== target = ARGV.shift.to_i n = [] ARGV.each do |a| n << Rational(a.to_i, 1) end hash = {} each_tree_permutation(n) do |tree| each_operations(tree) do |expr| v,s = eval(expr) if v == target puts s unless hash[s] hash[s] = true end end end
書いてみて:
どれも、今回の問題とはあんまり関係ないうえに、「だから何?」的な。
しまったぁ、 Enumerable::each_with_index (昨日 tdiary のソースをみてて知った) 使えばよかった。(自分で書きながらも、0.upto(a.size - 1) はないだろうと)
案の定、あとから見ると恥ずかしいところがぞろぞろですね。
とりあえず、each operations なんで複数なのか、とか。コメントが……とか。 でも、書き直すんだったら一年後(←なぜ?