わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

4つの8のパズル

 いきなりですが問題です.

 「8」の数を4つ使って,加減乗除をし,答えを求めます.
 例えば,8÷8+8÷8=2です.ここで「8÷8+8÷8」を,「2になる式」と呼びます.
 5になる式,6になる式,7になる式を,作ってください.

 解答の前に,補足です.数を連接させて,「88」「888」「8888」といった数にするのは禁止とします.カッコはOKとします.「8÷8+8÷8」も「(8÷8)+(8÷8)」も,2になる式ですが,「((8÷8)+8)÷8」は,「1.125(または8分の9)になる式」です.カッコの入れ子も差し支えなく,{}や[]は使用しないこととします.
 といったところで解答です.0から10までの各整数について,その値になる式の数と,具体的な式を1つずつ,示します.

0 ... 44通り
    ((8+8)-8)-8
1 ... 32通り
    ((8+8)-8)÷8
2 ... 1通り
    (8÷8)+(8÷8)
3 ... 2通り
    ((8+8)+8)÷8
4 ... 4通り
    (8×8)÷(8+8)
5 ... なし
6 ... 1通り
    8-((8+8)÷8)
7 ... 1通り
    ((8×8)-8)÷8
8 ... 9通り
    ((8-8)×8)+8
9 ... 2通り
    ((8×8)+8)÷8
10 ... 2通り
    ((8+8)÷8)+8

 5になる式はなく,6になる式,7になる式(と2になる式)は,それぞれ1通りだけでした.なお,2になる式の2組のカッコと,6になる式の外側,7になる式の内側のカッコは,除去しても結果が変わらず,異なる式と見なせます.しかしプログラムを書いてみると,このカッコの除去処理は容易ではなく,今回の出力では,いずれの式にもカッコを2つ入れ,演算子の適用の順序を明確にしました.
 総当たりで式を求めて出力するプログラムをRubyで作成し,Gistに置きました.
 「総当たり」の方針として,まず「『8』の数を4つ使った,加減乗除の式」として,次の形を考えます.

8 o1 8 o2 8 o3 8

 ここでo1, o2, o3は「+-×÷」のいずれかです.
 そしてo1, o2, o3の2項演算を,どの順番で適用するかによって,式が決まるというわけです.例えばo1に「÷」,o2に「+」,o3に「÷」を割り当てて,o1, o2, o3の順に演算を行うのなら,式は「((8÷8)+8)÷8」です.o1からo3までの割り当ては同じでも,o1, o3, o2の順にしたら,式は「(8÷8)+(8÷8)」になって答えも異なります.
 場合の数は,o1からo3までの割り当ては4の3乗で64通り,そして適用順は,3つの演算子の組み合わせだから3の階乗で6通り…とするわけにいきません.今回の式では,「o1, o3, o2の順」と「o3, o1, o2の順」は,同じ式になります(o1が「÷」,o2が「+」,o3が「÷」で,o3, o1, o2の順のときにも,式は「(8÷8)+(8÷8)」です).それらは「式」として同一なので,別カウントにしないこととし,結局,適用順は5通りとなります.総数は64×5=320通りです.
 式によっては分数や負の数のほか,0除算が発生することがあります(例えば「(8+8)÷(8-8)」).プログラムではこれも式として認め,内部で評価結果をnilにし,出力時にはNot a Numberを意味する「NaN」にしています.NaNになるのは15通りです.また最大の値は4096,最小の値は-504,分数になる中で最大と最小は\frac{65}{8}-\frac{63}{8}です*1


(同日追記)本文およびGistのプログラムコードを更新しました.5通りの適用順を忠実にプログラムコードにすると,以下のようになり,o1, o2, o3の出現順序はさまざまですが,4つの8に対応する,v1, v2, v3, v4はどれもこの順に出現しているのは,面白いところです.

  def eval(v1, v2, v3, v4, o1, o2, o3, d = 0)
    case d
    when 0
      # d == 0: ((8 o1 8) o2 8) o3 8
      v = op(o3, op(o2, op(o1, v1, v2), v3), v4)
    when 1
      # d == 1: (8 o1 8) o2 (8 o3 8)
      v = op(o2, op(o1, v1, v2), op(o3, v3, v4))
    when 2
      # d == 2: (8 o1 (8 o2 8)) o3 8
      v = op(o3, op(o1, v1, op(o2, v2, v3)), v4)
    when 3
      # d == 3: 8 o1 ((8 o2 8) o3 8)
      v = op(o1, v1, op(o3, op(o2, v2, v3), v4))
    when 4
      # d == 4: 8 o1 (8 o2 (8 o3 8))
      v = op(o1, v1, op(o2, v2, op(o3, v3, v4)))

*1:「8分の1プラスマイナス8」です.