モンティ・ホール問題

モンティ・ホール問題というのがある。

「プレイヤーの前に3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろにはヤギ(はずれを意味する)がいる。プレイヤーは新車のドアを当てると新車がもらえる。プレイヤーが1つのドアを選択した後、モンティが残りのドアの内ヤギがいるドアを開けてヤギを見せる。

ここでプレイヤーは最初に選んだドアを、残っている開けられていないドアに変更しても良いと言われる。プレイヤーはドアを変更すべきだろうか?」

Wikipediaの説明を読んでも、どうもよく分からない。プログラムを書いてシミュレーションしてみるとどうなるのだろうか。最近知ったarc4random()を使って、計算してみる。

#import <Foundation/Foundation.h>

const int N = 3;

// プレイヤーはモンティがヤギのドアを開いても選択を変えない
void montyHall(int n) { // n:試行回数
    int hit = 0;
    
    for (int i = 0; i < n; i++) {
        int car = arc4random() % N; // 商品の位置        
        int p = arc4random() % N; // プレイヤーが選んだ位置
        if (car == p)
            hit++;        
    }
    
    NSLog(@"ドアを変更しない");
    NSLog(@"%d/%d %f%%", hit, n, 1.0*hit/n*100);
}

// プレイヤーはモンティがヤギのドアを開いた後、選択を変える
void montyHall2(int n) { // n:試行回数
    int hit = 0;
    
    for (int i = 0; i < n; i++) {
        int car = arc4random() % N; // 商品の位置        
        int p = arc4random() % N; // プレイヤーが選んだ位置
        
        // モンティがヤギのドアを開ける
        
        // プレイヤーは選択したドアを変更する
        if (car != p)
            hit++;
    }
    
    NSLog(@"ドアを変更する");
    NSLog(@"%d/%d %f%%", hit, n, 1.0*hit/n*100);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        const int n = 10000000;
        montyHall(n);
        montyHall2(n);
    }
    return 0;
}

実行結果です。

ドアを変更しない
3333261/10000000 33.332610%
ドアを変更する
6666672/10000000 66.666720%

このプログラムで正しいのかはよく分からない。

そういえばと思って、『数学ガール』でこの問題を扱っていたのを思い出した。『数学ガール 乱択アルゴリズム』の1章で出てくる。そこでは全ての可能性を表にまとめて、確率を計算している。なるほど、表で考えるとわかりやすい。