1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105,...
● ● ●● ● ●● ●●● ● ●● ●●● ●●●● ● ●● ●●● ●●●● ●●●●● ① 1 ② 3 ③ 6 ④ 10 ⑤ 15
n * (n+1) / 2
例: 10 = 1 + 3 + 6 例: 18 = 6 + 6 + 6
同じ三角数を何度も使って分解してよい。
この定理はガウスによって証明された。
例: 12 = 6 + 6 12 = 1 + 1 + 10 12 = 3 + 3 + 6
自然数のうちで、三角数の和に分解したときに、なるべく分解の種類の多いものを求めたい。 以下の指示に従って、順にプログラムを作れ。
int tri(int n)を作りなさい。main() 関数は、
int main(void) { int i; for (i=1; i<10; i++) printf("tri(%d) = %d\n", i, tri(i)); return 0; }などとして、動作を確認せよ。
void sum_of_tri(int p)を作りなさい。分解のしかたは、自由に決めてよい。少なくとも1通りが表示されればよい。 main() 関数は、
int main(void) { sum_of_tri(10); sum_of_tri(12); return 0; }などとして、動作を確認せよ。
2つの三角数の和に分解することは、まだ考えなくてよい。(つまり、分解に失敗する例があっても構わない。)
ヒント
for (....) { for (....) { for (....) { sum = tri(i) + tri(j) + tri(k); if (sum == p) {
int num_of_sum_of_tri(int p)を作りなさい。
ヒント1:「3つ以下」の部分を、「ちょうど3つ、ただし0が混じってもよい」と解釈すると、プログラムが簡単になる。「tri(0) = 0」 なので都合がよい。
例: 6 = 0 + 0 + 6 6 = 0 + 3 + 3
ヒント2:重複する分解は、うまくループを回すことで、候補から除外できる。
例: 10 = 1 + 3 + 6 で1通りと数えるとすると、 10 = 1 + 6 + 3 や、 10 = 3 + 1 + 6 などは、探索しないように工夫すればよい。
出力例: 12 は 3 通りに分解できます。
num_of_sum_of_tri() 関数が、画面表示をしていると、時間がかかりすぎる。画面表示をやめれば、数秒で結果が出るようになるはずである。
num_of_sum_of_tri() 関数での探索に、無駄がないか検討せよ。
なお、gcc でのコンパイル時にオプションをつけると、同じプログラムのままでも実行速度が早くなる。
gcc -O2 hoge.cのように、"-O2"(マイナス・大文字オー・に)を付け加えるとよい。
Cygwin 環境で実行時間を測るには、
./a.exeを実行する代わりに、
time ./a.exeと、先頭に "time" を付けて実行すればよい。0.01 秒よりも細かい値が表示されるかもしれないが、かなりの誤差も含んでいる。信頼のおける値は 0.03 秒単位ぐらいである。
30 = 0 + 15 + 15 30 = 1 + 1 + 28 30 = 3 + 6 + 21 30 = 10 + 10 + 10
9?2 は 2? 通りに分解できます。
9??6 は 8? 通りに分解できます。
9??92 は 3?3 通りに分解できます。
(注意)? は伏字である。実際には数字1桁(0から9のどれか)である。