Collatz conjecture 解説!

プログラミング

皆様どうも、ばるとーくです!
今回はこちらの問題「Collatz conjecture」を解説していこうと思います!

問題

問題文

関数 $f(n)$ を以下のように定義する。

$$f(n) = \begin{cases} n/2 & (n \equiv 0 \pmod{2}) \\ 3n+1 & (n \not\equiv 0 \pmod{2}) \end{cases}$$

与えられた正の整数 $N$ を $n$ の初期値として、「$n$ を $f(n)$ で置き換える」操作を繰り返す。
これを $1$ 回以上行ったとき、初めて値が $1$ となるまでには何回の操作を必要とするか求めよ。
ただし、$10^{100}$回以内の操作で $1$ に到達しない場合は infinity と出力せよ。

制約

  • $1 \le N \le 3000$
  • $N$ は整数

解いてみたい方はこちら↓

ProblemId = 13413 - yukicoder
競技プログラミングの練習サイト

解説

この問題は有名な「コラッツ予想」をモティーフにして作りました。

コラッツ予想とは

このようなことを予想する問題です。

適当な自然数を1つ思い浮かべる。
「偶数なら2で割り、奇数なら3を掛けて1を足す」という操作を繰り返す。
最初の数がどんな数でも、計算を繰り返すうちに必ず1になる。

この問題は、コンピュータを用いた証明により $2^{68}$ 以下の数で正しいことが立証されているものの、未だ未解決な問題です。1

今回は、この「偶数なら2で割り、奇数なら3を掛けて1を足す」という部分の表現を関数として表していたわけです。
「操作結果が1になるまでに何回かかるか?」というところがこの問題独自の点です。

この問題で考えるべきポイントは3つです。

  1. 実装方法
  2. infinity の場合はどんなときか
  3. "$1$" の処理

始めに実装方法ですが、シンプルにwhileループを組むだけで問題ありません。
(yukicoder解説ページの想定解を参考にしてください)
関数 $f$ の根幹はif文で作ることができるでしょう。
また、後述しますが、この関数 $f$ はコード内で2回使用するため、関数化しておくと実装が少し楽になるでしょう。

次に、infinity の場合、すなわち、「$10^{100}$ 回以内の操作で $1$ にならないとき」はどんな時なのかについてです。
結論から言うと、それに該当する場合は今回の制約上ありません。ただのフェイク情報というわけです(この辺が共テ仕草です)。
実際、今回の制約内での最大の答えが $N=2919$ のときで、その計算結果は $216$ となります。

※参考:測定に使用したコードとその結果(Github)

Build software better, together
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over...

最後に1の処理です。問題文の制約として、「操作を $1$ 回以上適用したとき」というものがあるため、1を入力すると0が出力されるようなコードはWAとなります。
具体的には、(想定誤解法として用意していますが)このようなコードはWAとなります。
※疑似言語を使用しています

整数型 n
while(n != 1){
  ●関数fの処理を行う
}

●答えを出力

これを回避する方法として、想定解では、「whileループを回す前に1回だけ関数 $f$ の処理を回しておく」方式を採用しています。(もちろん他にも解法はあるはずです。)
この方式を採用するなら、先ほど言った通り、関数 $f$ の処理を2回書く必要があるので、関数化しておくと便利でしょう。

以上で解説を終わります。
想定解はyukicoderの解説ページにありますので、参考にしてください。
今回はPythonも主が書きました...!(実はちょっとだけ使えるマン)

Footnotes

  1. https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%A9%E3%83%83%E3%83%84%E3%81%AE%E5%95%8F%E9%A1%8C

タイトルとURLをコピーしました