Names in Boxes
100人の囚人パズルの正解戦略の確率を計算してみました。
ネタバレ含むので自分で考えたい人は見ないでください。
箱の中身を次の箱へのポインタとみなして連結リストを考えます。全てのリストは必ずループとなり、また一つの箱が二つ以上から参照されることはありません。ループが数字の6みたいな形になることはなく、必ず閉じた輪になるということです。
長さmのループを順にたどれば必ずm回で元の箱に戻ってくる(=自分の名前を引き当てる)ことができます。つまり全員が生き残るには長さ51以上のループが含まれないことが条件です。
n個の箱の中で、長さm以上のループができる確率pは次のようになります。
分母はn個の名前の配置の並べ替えの総数。
分子は長さ k∈[m..n] のループを持つ場合の数の和で、各項は
「長さ k のループの取り方の数 c(k)」×「最長ループに含まれない箱(n-k)個の並べ方の数」です。
c(k)は具体的には
となります。(kで割る = ループなのでどこが先頭かを区別しない)
これを p に代入してやると
と、調和数が出てきます。
n=100, m=51 で実際計算してみると、p = 0.688 となり、1-p = 0.312 で確かに30%を超える確率で全員助かることがわかります。おもしろいですね。
import Data.Ratio main :: IO () main = do let p = fromRational $ sum [ 1%k | k <- [51..100] ] print p print (1 - p) {- 0.6881721793101953 0.31182782068980475 -}