LoginSignup
4
3

More than 5 years have passed since last update.

円周率チャレンジで時間を溶かさないために

Last updated at Posted at 2018-11-08

この記事は円周率チャレンジの最適解が53であることを示し、
私のように無駄に52以下の解を探して時間を溶かさないようにするための記事です。
なお、当記事は円周率チャレンジの解法のネタバレを含みます。自己責任で閲覧ください。

円周率チャレンジについて

円周率チャレンジ

概要

円周率チャレンジを数学的に述べると次のような問題です。

g_1(x) = x + 2 \\
g_2(x) = \sqrt{x} 

とする。このとき
関数の列$f_1,\dots, f_n$ ただし$f_i \in { g_1, g_2}$であって
$$ \pi = f_1 \circ f_2 \circ \dots \circ f_n (0)$$
となるもののうち最も短いものを求めよ。

ランキングを見ると現状の最適解が53であることがわかります。
それでは52以下の解は存在するのでしょうか?

考察

今探している解の長さの上限を固定して$N$と置きます。具体的には$N = 53$
です。
このとき、最適解$f_1, \dots, f_n$に関する必要条件として以下のことが成り立ちます。

  • $f_n = g_1$として良い。
    • なぜなら$f_n = g_2$のときは$f_1, \dots, f_{n-1}$も解となり最適性に矛盾します。
  • $i < n$のとき$f_i$の引数の値($f_{i+1} \circ \dots \circ f_n (0)$のこと)は$1$以上$2 (n - i)$以下である。
    • これは数学的帰納法で示せます。

これらの性質を用いて解を$f_1$から順に枝狩り探索で探します。

解法

次のような疑似コードで示されるアルゴリズムは長さN以下の解を全探索します。
$\pi$からスタートするのがポイントです。

pi = 3.141592653589793
def dfs(f_1,...,f_k, v):
  if f_1 ... f_k(v) == pi:
    print f_1,...,f_k
  else:
    for f_{k+1} in [g_1, g_2]:
      v1 = f_{k+1}^{-1}(v) # f_{k+1}の逆関数
      if f_1 ... f_{k+1}(v1) == pi:
        print f_1,...,f_{k+1}
      elif 1 < v1 < 2(N - k - 1):
        dfs(f_1,...,f_{k+1}, v1)
def main():
  dfs([], pi)

このアルゴリズムをHaskellで実装してみるとちょうど長さ53の解が一つ見つかりました。
(ネタバレ防止のため解そのものはprintしていませんが、ネタバレしたくないひとは見ないことをおすすめします。)
実行結果

結論

円周率チャレンジの最適解は53です。52以下の解を探して時間を無駄にされませんように。

追記

とか書いていたら$N = 50$の解がランキングに載っていました。どういうことなの。。。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3