Project Euler

Project Euler 問題23(過剰数の和でない数)を解いてみる

Euler_023

Project Euler で紹介されている問題23を解いてみました。過剰数についての問題です。問題の説明で、完全数、不足数の定義も行っています。問題21で作った関数を再利用します。

Project Euler 問題23(過剰数の和でない数)

完全数とは、真の約数(その数より小さい、その数を割り切る数)の和がちょうど、その数に等しい数である。例えば、28 の真の約数の和は、1 + 2 + 4 + 7 + 14 = 28 となり、28 は完全数となる。

ある数 $n$ の真の約数の和が、$n$ より小さければ不足数、$n$ より大きければ、過剰数と呼ぶ。

12 の真の約数の和は、1 + 2 + 3 + 4 + 6 = 16 となり、最小の過剰数となる。このため過剰数2つの和と表せる最小の数は 24 となる。数学的な解析により、28123 より大きいすべての整数は、2つの過剰数の和として表されることが分かっている。2つの過剰数の和で表せない最大の数がこの上限よりも小さいことは分かっているが、この上限値より小さくすることはできていない。

2つの過剰数の和として表すことができない正の整数の和を求めよ。

解答例

問題21で真の約数の和を求める関数(calc_sum_of_divisors)を作りました。この関数を再利用します。問題のヒントを使って、28123以下の過剰数を求めます。求めた過剰数は、配列 abundant に格納していきます。なお配列 abundant のサイズは明らかに大きくとっています。過剰数の和で表せるかを配列 is_sum_of_abundant に格納します。具体的な手順は以下です。

  • is_sum_of_abundant の値をすべて0にする。
  • 配列 abundant から、過剰数を2つ取得する。
  • その和を添え字として is_sum_of_abundant の値を1にする。

配列 is_sum_of_abundant が0の数をすべて加えて解答を求めます。以下は、C の実装です。

#include <stdio.h>

#define LIMIT 28123

int abundant[LIMIT + 1];
int is_sum_of_abundant[LIMIT + 1];

int calc_sum_of_divisors(int number)
{
	int sum;
	int i;

	sum = 1; /* Add 1 (the first divisor) */
	for (i = 2; i * i <= number; ++i) {
		if ((number % i) == 0) {
			if (i * i != number) {
				sum += i;
				sum += number / i;
			} else {
				sum += i;
			}
		}
	}

	return sum;
}

int main(void)
{
	int i, j;
	int num_of_abundant;
	int sum = 0;

	for (i = 0; i <= LIMIT; ++i) {
		abundant[i] = 0;
		is_sum_of_abundant[i] = 0;
	}

	num_of_abundant = 0;
	for (i = 2; i <= LIMIT; ++i) {
		if (calc_sum_of_divisors(i) > i) {
			abundant[num_of_abundant] = i;
			++num_of_abundant;
		}
	}

	for (i = 0; i < num_of_abundant; ++i) {
		for (j = i; j < num_of_abundant; ++j) {
			if (abundant[i] + abundant[j] <= LIMIT) {
				is_sum_of_abundant[abundant[i] + abundant[j]] = 1;
			}
		}
	}

	for (i = 1; i <= LIMIT; i++) {
		if (is_sum_of_abundant[i] == 0) {
			sum += i;
		}
	}

	printf("Problem023: %d\n", sum);

	return 0;
}

補足

問題には、「28123 より大きいすべての整数は、2つの過剰数の和として表されることが分かっています」とあります。配列 is_sum_of_abundant の値が0になる最大の数は、20161 でした。結果的には、20161 より大きいすべての整数は、2つの過剰数の和として表されます。問題を少し解きにくくする意図があるのかもしれません。

最後に

「20161 より大きいすべての整数は、2つの過剰数の和として表されます」は、事実ですが、過剰数のほとんどは偶数のため、少し不思議に感じます。また、「プライムナンバーズ」(David Wells著 伊知地宏監訳 オライリージャパン 2008年)の「過剰数」の項には、「正の整数のだいたい24.8%が過剰数です。」とあります。

過剰数、不足数については、計算機で扱える興味深い問題が他にもありそうです。

引き続き、Project Euler の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA