用C语言验证“三门定理”

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>

// 一个源自博弈论的数学游戏问题:
// 参赛者会看见三扇门,
// 其中一扇门的里面有一辆汽车,
// 选中里面是汽车的那扇门,
// 就可以赢得该辆汽车,
// 另外两扇门里面则都是一只山羊。
// 当参赛者选定了一扇门,
// 主持人会开启另一扇是山羊的门;
// 并问:“要不要换一扇门?”
// 依照玛丽莲·沃斯·莎凡特的见解,参赛者应该换,
// 换门的话,赢得汽车的概率是2/3。
// 这问题亦被叫做蒙提霍尔悖论:
// 因为该问题的答案虽在逻辑上并无矛盾,
// 但十分违反直觉。

// 验证3门定理
// 1. 先验证不换门的情况
// 2. 再验证换门的情况

// 验证具体设计思路
// 1. 先创建一个10万次的循环实验;
// 2. 每个试验都有一个三个元素的数组;
// 3. 数组分别是两个0一个1;
// 4. 先随机交换3次数组;
// 5. 再随机选一个数组中的元素;
// 6. 此时,再分别检查另外两个数组,公布其中一个元素是0的数组;
// 7. 最后记录选中1的次数;
//

void Swap(int *a, int *b)
{
    int iTmp = *a;
    *a = *b;
    *b = iTmp;
}

bool GuessWithNoSwitch(void)
{
    // 1. 创建一个三个元素的数组
    static int arrInt[3] = { 0, 0, 1 };

    // 2. 先随机交换三个数组中元素的位置
    for (int iIdx = 0; iIdx < 3; ++iIdx)
    {

        // 2.2 获取两个随机数(0~2的范围内)
        const int iRandom1 = rand() % 3;
        const int iRandom2 = rand() % 3;

        // 2.3 交换两个数组元素
        Swap(&arrInt[iRandom1], &arrInt[iRandom2]);
    }

    // 3. 随机选中一个数组元素
    const int iRandom3 = rand() % 3;
    if (0 == arrInt[(iRandom3 + 1) % 3])
    {
        // 3.1 公布此数组元素是0
    }
    else if (0 == arrInt[(iRandom3 + 2) % 3])
    {
        // 3.2 或者公布此数组元素是0
    }

    // 4. 检查是否选中1
    bool bCheck = false;
    if (1 == arrInt[iRandom3])
    {
        bCheck = true;
    }

    return bCheck;
}

bool GuessWithSwitch(void)
{
    // 1. 创建一个三个元素的数组
    static int arrInt[3] = { 0, 0, 1 };

    // 2. 先随机交换三个数组中元素的位置
    for (int iIdx = 0; iIdx < 3; ++iIdx)
    {

        // 2.2 获取两个随机数(0~2的范围内)
        const int iRandom1 = rand() % 3;
        const int iRandom2 = rand() % 3;

        // 2.3 交换两个数组元素
        Swap(&arrInt[iRandom1], &arrInt[iRandom2]);
    }

    // 3. 随机选中一个数组元素
    int iRandom3 = rand() % 3;
    if (0 == arrInt[(iRandom3 + 1) % 3])
    {
        // 3.1 公布此数组元素是0,并且切换选中的元素为下面的((iRandom3 + 2) % 3)
        iRandom3 = (iRandom3 + 2) % 3;
    }
    else if (0 == arrInt[(iRandom3 + 2) % 3])
    {
        // 3.2 或者公布此数组元素是0,并且切换选中的元素为上面的((iRandom3 + 1) % 3)
        iRandom3 = (iRandom3 + 1) % 3;
    }

    // 4. 检查是否选中1
    bool bCheck = false;
    if (1 == arrInt[iRandom3])
    {
        bCheck = true;
    }

    return bCheck;
}

int main(int argc, char* argv[])
{
    // 1. 先设置伪随机数的种子
    srand((unsigned int)time(NULL));

    // 2. 打印交互语句
    printf("The first case: No witch choice!\n");

    // 3. 先设置最大选择次数(当前是十万次)
    const int iMaxCount = (int)1e5;

    // 4. 用于记录当前选中“数字1”的次数
    int iCntNoSwitch = 0;
    for (int iIdx = 0; iIdx < iMaxCount; ++iIdx)
    {
        if (GuessWithNoSwitch())
        {
            ++iCntNoSwitch;
        }
    }

    // 5. 计算第一种方式选中的“频率”
    const double dRatio1 = 1.0 * iCntNoSwitch / iMaxCount;
    printf("case 1 ratio: %lf\n", dRatio1);

    // 6. 打印交互语句
    printf("The second case: Witch choice!\n");

    // 7. 用于记录当前选中“数字1”的次数
    int iCntSwitch = 0;
    for (int iIdx = 0; iIdx < iMaxCount; ++iIdx)
    {
        if (GuessWithSwitch())
        {
            ++iCntSwitch;
        }
    }

    // 8. 计算第二种方式选中的“频率”
    const double dRatio2 = 1.0 * iCntSwitch / iMaxCount;
    printf("case 1 ratio: %lf\n", dRatio2);

    return 0;
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

James_Xue_2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值