プログラマメモ2 - programmer no memo2

モンティ・ホール問題 その1 2009/11/23

正直、いまだによく理解できてない確率問題 モンティ・ホール問題です。


プログラム書いたらうーんたしかにそうだなーと思うところありだけど、直感的にはどうも....

で、どうして再びこの問題を考えることにしたというのは、
たまたま―日常に潜む「偶然」を科学する
田中 三彦
4478004528

この本にのっていたからだけど、最近の確率を扱った本ではとりあげられますね。

詳しい説明はwikipeiaをみればわかりますが、自分の頭で「わかった」という感じになるまでちょい時間がかかりました。

愚直にシュミレートしてみて結果をおっていく過程でなんとなく「わかり」ました(と思う)。

プログラムは3つの箱のひとつにランダムに「あたり」を入れて、再びランダムに箱を選ぶパターンと、
ランダムに選んだ箱以外の箱を司会のモンティが開いてその逆を選ぶというパターンにしてみました。

最初のパターンは1/3となりますね。
つぎのパターンは説明として、司会者モンティかならず「あたり」の箱を開かないということが自明です。なので、その逆を選ぶというロジックにしたわけですが、何回か実行してみて大体2/3の割合で「あたり」がでるようです。
※プログラムがまちがっていなかったら。

まずは結果から
出力をひとつづつ追うとたしかに、わかってきます。
司会者モンティは、「かならず」あたりではない「やぎ」の箱を開きます!!

各 10回 試行します
[ヤギ] [ヤギ] [あたり]
あなたが選んだ箱は:[ヤギ]
[ヤギ] [ヤギ] [あたり]
あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが選んだ箱は:[あたり]
[ヤギ] [ヤギ] [あたり]
あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが選んだ箱は:[あたり]
[ヤギ] [あたり] [ヤギ]
あなたが選んだ箱は:[ヤギ]
[あたり] [ヤギ] [ヤギ]
あなたが選んだ箱は:[あたり]
[あたり] [ヤギ] [ヤギ]
あなたが選んだ箱は:[ヤギ]

[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[あたり] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[ヤギ] [あたり] [ヤギ]
あなたが最初に選んだ箱は:[あたり]
残りの箱:[ヤギ] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[ヤギ]
[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[あたり]
残りの箱:[ヤギ] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[あたり] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[あたり] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[ヤギ] [ヤギ] [あたり]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[ヤギ] [あたり]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[あたり]
残りの箱:[ヤギ] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[ヤギ]
[ヤギ] [あたり] [ヤギ]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[ヤギ] [あたり]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[ヤギ]
残りの箱:[あたり] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[あたり]
[あたり] [ヤギ] [ヤギ]
あなたが最初に選んだ箱は:[あたり]
残りの箱:[ヤギ] [ヤギ]
モンテぃは箱を開いた:[ヤギ] あなたが選んだ箱は:[ヤギ]

*** はじめの選択から変更しない場合
当たった回数: 3/10
*** はじめの選択から変更する場合
当たった回数: 6/10



この結果を選んだの恣意的になのだけど、大体こんな結果になります。
最初に選んだ箱を変えない場合は、「あたり」が3/10という結果に。

モンティの開いた箱の逆を選ぶ場合は、6/10という結果に。

以下作成したコード
Javaです。
import java.util.Random;

public class A_MontyHallproblem {

final static String BINGO = "あたり";

public static void main(String[] args) {
int trycount = 10;
int c1, c2 = 0;
System.out.println("各 " + trycount + "回 試行します");

{
c2 = b(trycount, false);

}
System.out.println();
{
c1 = b(trycount, true);

}

System.out.println();
System.out.println("*** はじめの選択から変更しない場合");
System.out.println("当たった回数: " + c2 + "/" + trycount);
System.out.println("*** はじめの選択から変更する場合");
System.out.println("当たった回数: " + c1 + "/" + trycount);
}

static int b(int tryCount, boolean rechoice) {
int c = 0;
for (int i = 0; i < tryCount; i++) {
boolean b = a(rechoice);
// System.out.println();
if (b)
c++;
}

return c;
}

static boolean a(boolean rechoice) {
String[] box = box();
for (String s : box) {
System.out.print("[" + s + "] ");
}
System.out.println();

int yourFirstChoice = yourChoice(3);

//
if (rechoice) {

String[] box2 = new String[2];
int pos = 0;
for (int i = 0; i < 3; i++) {
if (yourFirstChoice != i) {
box2[pos++] = box[i];
}
}
System.out.println(" あなたが最初に選んだ箱は:[" + box[yourFirstChoice] + "]");
// 残りの箱
System.out.print(" 残りの箱:");
for (String s : box2) {
System.out.print("[" + s + "] ");
}
System.out.println();
// モンテぃは必ず当たりじゃないものを選ぶので、その逆をあなたは選択するとします。
if (!box2[0].equals(BINGO)) {
System.out.println(" モンテぃは箱を開いた:[" + box2[0]
+ "] あなたが選んだ箱は:[" + box2[1] + "]");
return box2[1].equals(BINGO);
}
System.out.println(" モンテぃは箱を開いた:[" + box2[1] + "] あなたが選んだ箱は:["
+ box2[0] + "]");
return box2[0].equals(BINGO);
} else {
System.out.println(" あなたが選んだ箱は:[" + box[yourFirstChoice] + "]");
if (box[yourFirstChoice].equals(BINGO)) {
return true;
}
}

return false;
}

static int yourChoice(int c) {
Random random = new Random();
return random.nextInt(c);
}

static String[] box() {
String[] box = { "ヤギ", "ヤギ", "ヤギ" };
Random random = new Random();
int i = random.nextInt(3);
box[i] = BINGO;
return box;
}
}

: