のてすきあ − 完全独習非プログラマー −

Haskell で Project Euler を解く素人遊び

Problem 44

五角数同士の和と差がいずれも再び五角数になるものを探し、その差が最小となるものを見つける。

 五角数についてはコチラ(ウィキペディア:五角数)。 英語版の方が情報が充実しており、今回は英語版から五角数の判定法を拝借した。

 さて、この問題は随分と悩んだが、一向に早くならずに最後は妥協してしまった。全検索が絶望的なのは、やってみなくても予想がつくが、それ以外の方法が思いつかない。唯一の工夫は、検索の範囲を明確にするために、リストを2つに分けたところである。

 所望の組を(Pi, Pj)とし、Pi + Pj = S, Pi - Pj = Dと置くと、S,Dもまた五角数なのは問題からの要請の通りである。この時に、S + D = 2Pi となるので、 D < Pi < S という大小関係が成立している。そこで五角数のリストを先頭から順に調べるにあたって、Pi より小さな五角数のリストdsとPiから2Piまでの五角数のリストの2つを考えた。Dは前者、Sは後者の要素となっているはずである。このようにしてD+S=Piとなる組を見つけた後、S-D=2Pjを考慮して、S-Dがまた五角数になるような組(D,S)が見つかれば、そのDが求める答えである。Dが最小であることの保証は、五角数Piを小さい方から順に評価していることから得られる。(と思っているが厳密には確認していない…)  (S-D)はdsの要素となっているはずなので、elemを使って評価しても良いが、それよりも(S-D)が五角数であることを直接判定する方が早い。早いと言っても遅いが、早い。    計算の遅さは、見つけるべき答えが思いのほか巨大な数になることだろう。探索範囲を絞るような条件を見いだせれば計算も早くなると思うのだが…。

 ちなみに、もっとどストレートに五角数の組み合わせを虱潰しに探しまくる方法でも、実はそれほど変わらない時間で答えに辿り着く。まぁ、ドンマイということである。

プログラマの限界か…★★★