三门问题_java模拟测试

三门问题(Monty Hall problem)

昨天在刷douyin时,恰巧刷到了一条关于数学概率的小视频。点赞人数很多,评论人数也很多,重点是视频的内容谈到的三门问题确实非常的吸引人去思考(反正我有被吸引到,谢谢)。。

视频很短,结尾处就把“答案”说出来了。

当然,以我这脑瓜子,拿着手机愣是想了半个多小时,依然没弄明白为啥我的想法与公布的答案不符,一度让我怀疑我的智商。翻看了一下评论区,大家的想法和意见也都有分歧,有和我想的一样的,也有和公布的答案一样的,还很热心的把原因讲解了一遍,,,嗯,我还是没搞懂。

 

进入正题

首先看一下什么是“三门问题”。接下来是度娘登场时间~~~

三门问题(Monty Hall problem)亦称为蒙提霍尔问题、蒙特霍问题或蒙提霍尔悖论,大致出自美国的电视游戏节目Let's Make a Deal。问题名字来自该节目的主持人蒙提·霍尔(Monty Hall)。参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门可赢得该汽车,另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门会否增加参赛者赢得汽车的机率。如果严格按照上述的条件,那么答案是会。不换门的话,赢得汽车的几率是1/3。换门的话,赢得汽车的几率是2/3。

以上的说法可能不是很严谨哈,下面给出更为严谨的陈述:

  • 现在有三扇门,只有一扇门有汽车,其余两扇门的都是山羊。

  • 汽车事前是等可能地被放置于三扇门的其中一扇后面。

  • 参赛者在三扇门中挑选一扇。他在挑选前并不知道任意一扇门后面是什麽。

  • 主持人知道每扇门后面有什么。

  • 如果参赛者挑了一扇有山羊的门,主持人必须挑另一扇有山羊的门。

  • 如果参赛者挑了一扇有汽车的门,主持人等可能地在另外两扇有山羊的门中挑一扇门。

  • 参赛者会被问是否保持他的原来选择,还是转而选择剩下的那一扇门。

嗯,陈述看完,就要讲讲为啥换门后中奖的概率要高了。(解法很多,这里只列举一种比较通俗易懂的解题思路,依然来自度娘,,,感谢度娘的大力支持,谢谢。。)

          当参赛者转向另一扇门而不是维持原先的选择时,赢得汽车的机会将会加倍。

          有三种可能的情况,全部都有相等的可能性(1/3):

          1、参赛者挑山羊一号,主持人挑山羊二号。转换将赢得汽车。

          2、参赛者挑山羊二号,主持人挑山羊一号。转换将赢得汽车。

          3、“参赛者挑汽车,主持人挑羊一号。转换将失败”,和“参赛者挑汽车,主持人挑羊二号。转换将失败。”此情况的可能性为:1/3 * 1/2 + 1/3 * 1/2 = 1/3。

 

实践部分

既然我无法用脑瓜子想透它,就要用行动证明它!

我预想的证明方法就两种:

方法一:用扑克牌

        首先用两张一样数字的扑克代表山羊,一张不一样数字的扑克代表汽车,然后叫上你的小伙伴,愉(枯)快(燥)的玩游戏!你的小伙伴扮演主持人,你就是玩家,根据规则开始不断地猜猜猜、换换换、不换不换我不换,同时记录猜中的次数、不中的次数与总次数,最后再计算换与不换能猜中汽车的概率。

这个方法确实简单,但是也确实耗时。而且我们知道,概率这东西,尝试的次数越多,才越接近真实情况。玩个十万次估计能把人玩废,哈哈哈。

方法二:用代码模拟

上代码~~~(代码很简单,学过java的都知道)

import java.util.Random;
import java.util.Scanner;

/**
 * @Description 三门问题模拟
 * @Author HeHuanxing
 * @Date 2020/12/13 22:42
 * @UpdateUser
 * @Version 1.0
 */
public class ThreeQuestionsTest {

    // 测试的次数(即竞猜的总次数)
    private static float numberOfGuesses = -1;
    // 玩家选择的门编号
    private static int selectedNumber = -1;
    // 主持人开启背后有山羊的门编号
    private static int doorOpenedIndex = -1;
    // 猜中的总次数
    private static float numberOfAwards = 0L;
    // 未猜中的总次数
    private static float noAwards = 0L;
    // 玩家是否更换所选择的门(默认不更改)
    private static String isChangeChoice = "N";
    // 使用长度为3的数组表示三个门,初始值为-1,表示不代表任何东西;使用1表示汽车,2表示羊
    private static int[] doors = new int[]{-1, -1, -1};
    // 使用Random对象获取随机数,模拟随机分配汽车和山羊
    private static Random randomForAssigned = new Random();
    // 同样使用Random对象获取随机数,模拟随机选择一扇门
    private static Random randomForSelection = new Random();

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入想要测试的次数:");
        numberOfGuesses = input.nextFloat();
        System.out.println("是否更换所选择的门?(Y/N)");
        isChangeChoice = input.next();
        System.out.print("输入完成,总的竞猜次数为" + numberOfGuesses + "次,并且");
        if (isChangeChoice.equalsIgnoreCase("N")) {
            System.out.println("当主持人询问是否更换门时,玩家选择不更换");
        } else {
            System.out.println("当主持人询问是否更换门时,玩家选择更换");
        }

        startTheGuessingGame();
    }

    private static void startTheGuessingGame() {
        for (int num = 1; num <= numberOfGuesses; num++) {
            // 每进行一次选择,均需要初始化一次各个参数,模拟这是一场新的竞猜环节
            init();

            // 随机在三个门后分配汽车和山羊
            randomlyAssigned();

            // 随机选择任意一扇门
            randomSelection();

            // 主持人开启背后有山羊的门,并根据玩家是否愿意换门来进行交换门编号
            askAndDetermineTheFinalChoice();

            // 累计猜中的次数与未猜中的次数
            if (doors[selectedNumber] == 1) {
                numberOfAwards++;
            } else {
                noAwards++;
            }
        }
        System.out.println("猜中汽车的概率是:" + numberOfAwards/numberOfGuesses);
        System.out.println("猜不中汽车的概率是:" + noAwards/numberOfGuesses);
    }

    /**
     * 将各个参数初始化
     */
    private static void init() {
        selectedNumber = -1;
        doorOpenedIndex = -1;
        doors[0] = -1;
        doors[1] = -1;
        doors[2] = -1;
    }

    /**
     * 随机在三个门后分配汽车和山羊
     * 编号说明:使用1表示汽车,使用2表示山羊
     */
    private static void randomlyAssigned() {
        int carIndex = randomForAssigned.nextInt(3);
        doors[carIndex] = 1;
        for (int index = 0; index < doors.length; index++) {
            if (index != carIndex) {
                doors[index] = 2;
            }
        }
    }

    /**
     * 随机选择任意一扇门
     */
    private static void randomSelection() {
        selectedNumber = randomForSelection.nextInt(3);
    }

    /**
     * 主持人开启背后有山羊的门,并根据玩家的换门意愿来进行下一步操作
     * 需要明确的是:主持人一定知道门后是汽车还是山羊,打开的一定是山羊的门
     */
    private static void askAndDetermineTheFinalChoice() {
        // 确定被主持人打开的门编号
        for (int index = 0; index < doors.length; index++) {
            if (selectedNumber != index && doors[index] == 2) {
                doorOpenedIndex = index;
                break;
            }
        }

        if (isChangeChoice.equalsIgnoreCase("Y")) {
            // 若玩家愿意更换前面选中的那一扇门,则玩家交换后选中的即是另一扇没打开的门
            for (int index = 0; index < doors.length; index++) {
                if (selectedNumber != index && doorOpenedIndex != index) {
                    selectedNumber = index;
                    break;
                }
            }
        } else {
            // 玩家不愿意更换前面选中的那一扇门,则保持原状
            // do nothing
        }
    }
}

以下是测试结果:

更换门的测试:

请输入想要测试的次数:
1000000
是否更换所选择的门?(Y/N)
Y
输入完成,总的竞猜次数为1000000.0次,并且当主持人询问是否更换门时,玩家选择更换
猜中汽车的概率是:0.666836
猜不中汽车的概率是:0.333164

不更换门的测试:

请输入想要测试的次数:
5000000
是否更换所选择的门?(Y/N)
N
输入完成,总的竞猜次数为5000000.0次,并且当主持人询问是否更换门时,玩家选择不更换
猜中汽车的概率是:0.3335684
猜不中汽车的概率是:0.6664316

不论以扑克牌的方式方式验证,还是使用代码去测试,确实换门比不换门,猜中汽车的概率要高。不换门则仅有1/3概率,换了之后,有2/3概率把车开回家!

 

小尾巴~~~~~

博客账号申请了这么久,却一直没写过文章,这个就当做是一个开头吧。祝自己也祝所有人都能前程似锦 [手动加笑脸]

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值