ふと私は研究的なことをしたくなりました。C++で。ということでモンティ・ホール問題についての検証をしてみました。
モンティ・ホール問題についてはここを参照してください。知ってる前提で話は進みます。
普通はドアが3つあってヤギが2匹いますが、今回はココを色々いじってみようということです。
動作環境
Windows10 1903
VisualStudio 2019 Community(v142)
C++14 (競プロのプロジェクトを流用したため。設定変えるの忘れてた。再検証はめんどいのでしません。一緒やろうし)
ソース
#include<fstream>
#include <string>
#include <random>
constexpr int DOOR = 3; //ドアの数
constexpr int CAR = 1; //景品(車)の数
constexpr int TIMES = 100000; //試行回数(EXCELの行数的に10万で)
#define CHANGE //ドアを変えるかどうかのマクロ
int main() {
std::string name = std::to_string(DOOR) + '_' + std::to_string(CAR)
#ifdef CHANGE
+ "_Change"
#endif
+ ".csv";
std::ofstream file(name);
for (int iiiiii = 0; iiiiii < TIMES; iiiiii++) {
std::random_device seed_gen;
std::mt19937 engine(seed_gen());
std::uniform_int_distribution<> dice(0, DOOR - 1);
bool car[DOOR] = { false };
for (int i = 0; i < CAR; i++) {
int v = -1;
while (true) {
v = dice(engine);
if (car[v]) continue;
else break;
}
car[v] = true;
}
int select = dice(engine);
int open = -1;
for (int i = 0; i < DOOR; i++) {
if (i != select && !car[i]) {
open = i;
break;
}
}
#ifdef CHANGE
for (int i = 0; i < DOOR; i++) {
if (i != select && i != open) {
select = i;
break;
}
}
#endif
file << (car[select] ? "1" : "0") << '\n';//1が出力されれば正解、0が出力されれば不正解
}
}
EXCELで全て集計してます。
やりやすいように、マクロで変更が効くようにしてあります。
変数名がiiiiii
とか適当なところは突っ込まないで。
間違ってたら教えて。あれば再検証します。
#結果
ドア | 車(景品) | 変えるか | 確率[%] |
---|---|---|---|
3 | 1 | YES | 66.825 |
3 | 1 | NO | 33.273 |
4 | 1 | YES | 50.009 |
4 | 1 | NO | 25.082 |
4 | 2 | YES | 83.234 |
4 | 2 | NO | 49.982 |
5 | 1 | YES | 40.095 |
5 | 1 | NO | 20.074 |
5 | 2 | YES | 70.117 |
5 | 2 | NO | 40.060 |
5 | 3 | YES | 89.931 |
5 | 3 | NO | 59.951 |
結構しっかり出てくれました。
別に扉変えない場合は単純な計算でいいので、やる必要は一切ないのですがまあついでに。車の数がドアの数に対して2少ないのがないのは、100%になるからです。わかりますよね?
結果としては、一つ不正解が提供される場合は、変更するほうが圧倒的に良いです。
確率の計算とか大嫌いなので、数学的説明はしません。というかできません。
他にやりたいこと
開ける扉の数を変える
もっと台数とか増やす(しんどいので気が向けば。そう、気が向けば。)
#あとがき
モンティ・ホールのコードって結構簡単にかけるもんですね。
これCSV出力する必要なかったんじゃ...?