Project Euler – 問題21

d(n)をnの真の約数(nの約数でnより小さいもの)の和と定義する。

a≠bでd(a)=bかつd(b)=aのとき、aとbは友愛数と呼ばれる。

例えば220の真の約数は1,2,4,5,10,11,20,22,44,55,110なので、d(220)=284と なる。284の真の約数は1,2,4,71,142なので、d(284)=220となる。

10000未満の全ての友愛数の和を求めよ。

友愛数とは2つの異なる自然数a,bで自分自身を含まない約数の和が他方と等し くなるものである。まずは問題12で定義したfactorsを元に自分自身を含まない 約数のリストを求めるproperFactorsを定義する。1で割り切れるか試す部分を 特別扱いし2以降についてはfactorsと同様に処理することで自分自身を含まな い約数のリストを求めることができる。

次に友愛数かどうかのチェックをする関数amicableを定義する。ここでは友愛 数の定義をそのまま実装し、引数aの約数の和bを求め、aとbが異なり、bの約数 の和がaであった場合に友愛数であると判定する。最後に10000未満の数のリス トからfilterで友愛数を取り出しsumで和を求める。

properFactors n  = 1 : p' n 2 []
    where p' n x l
              | x * x > n      = l
              | x * x == n     = x : l
              | n `mod` x == 0 = x : p' n (x + 1) ((n `div` x) : l)
              | otherwise      = p' n (x + 1) l

amicable a = b /= a && (sum $ properFactors b) == a
    where b = sum $ properFactors a

euler021 = sum $ filter amicable [1..9999]