Project Euler で紹介されている問題9を解いてみました。素直なプログラム例とピタゴラス数が満たす性質を使った解き方を紹介します。
問題9(特別なピタゴラス数)
次の式を満たす3つの自然数
例)
解答例
方針としては、
検算をするために解答に加えて、求めたピタゴラス数も出力しています。C 言語での実装例です。
#include <stdio.h>
#define SUM 1000
int main(void)
{
int a, b, c;
for (a = 1; a <= (SUM/3); ++a) {
for (b = a + 1; b <= (SUM/2); ++b) {
c = SUM - (a + b);
if (b < c) {
if (a * a + b * b == c * c) {
printf("Problem009: %d\n", a * b * c);
printf("Problem009: a:%d b:%d c:%d\n", a, b, c);
}
}
}
}
return 0;
}
プログラムは、条件をみたすピタゴラス数をすべて出力します。プログラムを動作させると、問題に記載されている通り、1通りしか解が出力されないことも確認できます。
考察
この問題は、工夫すれば、手計算でも解を求めることができます。
原始ピタゴラス数
例えば、
次の事実(定理)が古代ギリシャですでに知られていました。証明は省略します。
自然数
とすると、
逆にすべての原始ピタゴラス数は、この形で表すことができる。
問題に適用する
つまり、すべてのピタゴラス数は、原始ピタゴラス数を
これから
一方、
ここで、
小さな値から調べる | ||
1 | 2 | ×( |
2 | 5 | ×( |
4 | 5 | 〇( |
4 | 25 | ×( |
5 | 10 | ×( |
10 | 25 | ×( |
20 | 25 | 〇( |
25 | 候補が存在しない | × |
解が2つでたように表から読み取れますが、
ピタゴラス数がもつ性質によって、解答を求めることができました。
解答案(改善版)
考察したロジックをプログラムに落とし込みます。手計算では素因数から候補を求めましたが、プログラムの場合は、2重ループで、
#include <stdio.h>
#define SUM 1000
int main(void)
{
int m, n, k;
int a, b, c;
for (n = 1; n * n <= SUM; ++n) {
for (m = n + 1; m * m <= SUM; ++m) {
if ((SUM / 2)%(m *(m + n)) == 0) {
k = (SUM / 2)/(m *(m + n));
if ((m * m - n * n)<= 2 * m * n) {
a = k *(m * m - n * n);
b = k * 2 * m * n;
} else {
a = k * 2 * m * n;
b = k *(m * m - n * n);
}
c = k *(m * m + n * n);
printf("Problem009: %d\n", a * b * c);
printf("Problem009: a:%d b:%d c:%d\n", a, b, c);
printf("Problem009: m:%d n:%d k:%d\n", m, n, k);
}
}
}
return 0;
}
素直なプログラムは、1000に対して、1000/2、1000/3 まで調べています(工夫すれば、もう少し小さくできます)。一方、考察に従ったプログラムは、
最後に
素直なプログラムを提示したあと、ピタゴラス数を生成する式から解答を求めてみました。
今回の問題を解くためには使いませんでしたが、高校数学の数学A「整数の性質」の範囲で、余り(合同式)を使う証明として、以下の例がよくでてきます(a、b、c はピタゴラス数とします)。
- a、b のうち、少なくともひとつは、3の倍数である。
- a、b のうち、少なくともひとつは、4の倍数である。
- a、b、c のうち、少なくともひとつは、5の倍数である。
ピタゴラス数は、昔から知られていますが、興味深い性質が多くあるようです。
引き続き、Project Euler の問題を紹介していきます。