引き続き問題を解いていきます。
問題はプログラマ脳を鍛える数学パズルより。
今回の問題
数学の未解決問題の1つに「コラッツの予想」があります。
コラッツの予想自然数nについて
・nが偶数の場合、nを2で割る
・nが奇数の場合、nに3をかけて1を足す
という操作を繰り返すとき、初期値がどんな数があっても必ず1に到達する(1→4→2→1のように繰り返す)
この予想の内容を少し変えて、初期値が偶数の場合、初回のみnに3をかけて1を足すことから始めることとし、「最初の数」に戻るものを考えます。
例えば、2で始めた場合は以下のようになります。
2→7→22→11→(中略)→2
同様に、4で始めると以下のようになります。
4→13→(中略)→4
しかし、6で始めると
6→(中略)→
となり、6に戻ってくることはありません。
問題
10000以下の偶数のうち、上記の2や4のような「最初の数に戻る数」がいくつあるか、その個数を求めてください。
実装手順
①2から10000までの偶数をループさせて初期値(最初の数)を設定する
②初期値に3をかけて1を足す
③上記で設定した値が初期値に戻るか、1になるまでループさせる
④上記のループ文の中で値が偶数、奇数の場合で処理を分ける
⑤値が初期値と一致した回数を数える
⑥出力する
書いたPHPコードと出力結果
<?php
// 問題の条件を満たす数字をカウントする変数
$count = 0;
// ①2から10000までの偶数をループさせて初期値を設定する
for ($initial_number = 2; $initial_number <= 10000; $initial_number += 2) {
// ②初期値に3をかけて1を足す処理
$original = $initial_number*3+1;
// ③$originalが初期値に戻るか、1になるかするまでループさせる
while ($original !== $initial_number && $original !== 1) {
// ④偶数、奇数の場合で処理を分ける
if ($original%2 === 0) {
$original = $original/2;
} else {
$original = $original*3+1;
}
// ⑤$originalが$initial_numberと一致すれば$countに1を足す
if ($original === $initial_number) {
$count = $count + 1;
}
}
}
// ⑥結果を出力する
echo $count;
// 結果
34
今回の学び
・ループ文の使い分け。今まではforeach80%、for20%のくらいの割合で使用していたがwhileが使いやすい場面もある。
・for文の第3引数の設定で、どのくらいの間隔でループ処理するか柔軟に変えられる。