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

Haskell で Project Euler を解く素人遊び

Problem 23

約数の和が自分自身より大きな数をabundant numberと呼ぶ。28123より大きな数は全て2つのabundant numberの和として表せるが、28123以下の数では必ずしもそうではない。2つのabundant numberの和で表せない全ての数の和を求める。

abundant number はリスト内包表記を使えば網羅できそうだ。あとはそれらの和で表せない数というのをどのように表現するか。表せない数のリストが得られれば、その和を取るだけなのだが…。

しばらく悩んだが、欲しいのは表せない数のリストではなく、表せない数の和だと気付いた。そして表せる数はもうリストになっているのだから、全体の和から表せる数の和を引けば、残りが欲しい和になる。

しれっとdivsSumなる関数を使っているが、これはproblem21の使い回しである。

さて、上記のコードで答えは出るものの、ハッキリ言って遅い。しかし試行錯誤を繰り返すも、抜本的な改善には至らなかった。現状ではこれ以上速いコードが見つからない。


mksumsという関数は2つのabundant numberの和で表される数を網羅する関数である。全ての組み合わせを作るために、はじめはリスト内包表記を使った普通の方法を採用していたが、それよりもzipWithを使ってみた方が少しだけ早かった。 また、28123以下の数だけを対象にすれば良いので、filter ( < 28123 ) をしようとしたが、それよりも sort.takeWhile ( < 28123 )の方が早かったのでそうした。nubは重複を削除する関数で、いくつかの実装があるが、知られているものをいくつか試したが、処理速度に大きな違いは見られなかった。

というわけで、引き続き改善を模索する。

★★★