最近見た数学パズル、あるいは本質を見ることの難しさ
イントロ
数学についての動画を投稿する YouTube チャンネルえびまラボが「平面上の10点は半径1の円盤を敷き詰めて必ず覆えるか?」という問題を紹介していた。
この問題の考案者はパズル作家の稲葉直貴氏で、この問題を考案した際の経緯が、本人が日本オペレーションズ・リサーチ学会に寄稿した記事パズル作家の発想法に書かれている。
本題
同記事には興味深いパズルが載っていた。
問題
フエール博士は非常に興味深い現象を発見した.細菌A は,1 分経過するごとに1 匹の細菌Bを食べ,2 匹に分裂する.これに対し,細菌B は仲間たちが食べられるたびに,2 匹に分裂するのだ.今,細菌B が30 匹入っている瓶の中に,分裂したばかりの細菌A を1 匹入れたとすると,この瓶の中から細菌B がいなくなるのは何分後か.
想定された解答
この問題は有名な問題 The Lost Hat の応用であるという。これはボートの速度・川の流速・落とした帽子までの距離が与えられたうえで帽子に追いつくまでの時間を求める問題であるが、帽子・ボートともに同じだけ川の流れの影響を受けるため、川の流速は無視してただ距離を速度で割ればよいのであった。一見これら2つの問題は似ても似つかないが、細菌の問題にも川の流速と同じく無視しても良い要素がある――細菌の分裂である。分裂の前後で細菌A 1匹あたりの細菌Bの数は変化しないため、細菌が分裂しないものと考えてもBがいなくなる時間に影響はなく、答えは30分後となる。
Python による検証
この理屈が本当に有効なのか俄には信じがたかったので、 Python で検証を行ってみた。
Python コード
a = 1
b = 30
t = 0
while b > 0:
t += 1
b -= a; a *= 2
b *= 2
print(f"{t = }, {a = }, {b = }, {b/a = }")
出力
t = 1, a = 2, b = 58, b/a = 29.0 t = 2, a = 4, b = 112, b/a = 28.0 t = 3, a = 8, b = 216, b/a = 27.0 t = 4, a = 16, b = 416, b/a = 26.0 t = 5, a = 32, b = 800, b/a = 25.0 t = 6, a = 64, b = 1536, b/a = 24.0 t = 7, a = 128, b = 2944, b/a = 23.0 t = 8, a = 256, b = 5632, b/a = 22.0 t = 9, a = 512, b = 10752, b/a = 21.0 t = 10, a = 1024, b = 20480, b/a = 20.0 t = 11, a = 2048, b = 38912, b/a = 19.0 t = 12, a = 4096, b = 73728, b/a = 18.0 t = 13, a = 8192, b = 139264, b/a = 17.0 t = 14, a = 16384, b = 262144, b/a = 16.0 t = 15, a = 32768, b = 491520, b/a = 15.0 t = 16, a = 65536, b = 917504, b/a = 14.0 t = 17, a = 131072, b = 1703936, b/a = 13.0 t = 18, a = 262144, b = 3145728, b/a = 12.0 t = 19, a = 524288, b = 5767168, b/a = 11.0 t = 20, a = 1048576, b = 10485760, b/a = 10.0 t = 21, a = 2097152, b = 18874368, b/a = 9.0 t = 22, a = 4194304, b = 33554432, b/a = 8.0 t = 23, a = 8388608, b = 58720256, b/a = 7.0 t = 24, a = 16777216, b = 100663296, b/a = 6.0 t = 25, a = 33554432, b = 167772160, b/a = 5.0 t = 26, a = 67108864, b = 268435456, b/a = 4.0 t = 27, a = 134217728, b = 402653184, b/a = 3.0 t = 28, a = 268435456, b = 536870912, b/a = 2.0 t = 29, a = 536870912, b = 536870912, b/a = 1.0 t = 30, a = 1073741824, b = 0, b/a = 0.0
30分後に細菌Bがきっちり0個になること、B/Aの比が1分に1ずつ減っていることがわかる。
微分方程式による解法
このような現象が必然的であることを確認するため、数値計算ではなく解析的に解きたくなったので、分裂による変化を連続関数で近似して微分方程式を立ててみた (差分方程式が解ければそのまま扱えるのかも) 。初期条件と単位ステップあたりの変化を記述するのは Python でやったことと共通だ。
時間の単位を分としているため、第2式の の係数 (捕食によるBの減少) を 1 [min⁻¹] とすることができる。また、1分毎に2倍という条件から
とわかる。
細菌A 1個あたりを考える
細菌A 1個あたりのBの数を考えるため、を一つの変数とみなしてこれを微分する (商の微分公式が覚えられないため、逆数をマイナス1乗とみなして積の微分でやっている) 。
ここで立てた微分方程式を代入すると、
となる。すなわち、 はきれいに消え、
の変化量は分裂速度や2種の細菌の量によらず一定であることがわかる。また、この式の両辺を
で積分すると
となり、 は線形に減っていき 30 分後には 0 になることがわかる。 Python で確認した現象は必然だったといえる。
積分因子法で機械的に解く
この微分方程式を正攻法で解くとしたらどのような方法になるのか気になったので、ChatGPTに解いてもらった (この程度ならハルシネーションなく解けるようだ) 。まず については変数分離法で簡単に解け、
。これより
について、
となるが、ここで両辺に積分因子
をかける。すると
となり、この左辺は を微分した形になっているので、
が導かれる (この変形がピンとこないのだが、微分して元の形に戻ることは確認できる) 。あとは両辺を積分して
初期条件より なので、
となり、30分後に細菌Bが消滅することがわかる。
考察
ところで、積分因子としてかけた だが、これは要するに
だ (マイナス1乗は逆数なので) 。このことから
- 細菌A 1個あたりを考えるとうまく解けるのは突飛なひらめきではなく必然である。
- 上記の2つの解法は本質的には同一である。
などと言うことができるのかもしれない。
おまけ
冒頭で紹介したえびまラボの別の動画では、足して15になる3つの数を取るターン制ゲームの必勝法を考える問題が出題される。動画を見進めるとこれもまた、一見まったく異なる2つの問題が本質的に同一である例であるとわかる。