“三门问题”:数学经典概率问题,用java代码求证

趣味编程,java求证“三门问题”

三门问题,也称为蒙提霍尔问题(Monty Hall Problem)。

题意如下:

假如你参加一档选秀节目,节目中一共有三道关闭着的门,其中一扇门后面是车另外两扇门后面是羊,主持人能看到后面是什么,现在让你选,只要你选中的门后面有车,车就送给你。

现在你选中一扇门但不打开,主持人在剩下两扇门中打开一扇后面为羊的门(主持人知道所有门后面的情况),现在只剩下两扇门,主持人再给你一次选择的机会,问题来了,为了拿到车,你是继续坚持原来的选择,还是换一扇门?

“三门问题”:数学经典概率问题,用java代码求证_第1张图片

一开始作者认为选择哪一道门得车的概率看起来好像都是1/2,但答案是换一道门的概率为2/3。于是作者走上代码求证的道路。

示例代码如下:


import java.util.*;

class TestSanMen{ 

    private boolean flag; // true为车 false为羊

    private int doorNumber; // 门牌号 1 、2 、3

    public TestSanMen(int random,boolean flag){
        this.doorNumber = random;
        this.flag = flag;
    }

    public boolean getFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getDoorNumber() {
        return doorNumber;
    }

    public void setDoorNumber(int doorNumber) {
        this.doorNumber = doorNumber;
    }
}


public class SanMenQuestion {

    public static void main(String[] args) {
        //序号1-1000次(总次数) 每次选择的情况  
        Map<Integer, List<TestSanMen>> map = new HashMap<>();
		// 总次数
        double sunNumber = 1000;
		// 次数越多,概率越精准
        for (Integer i = 1; i<=sunNumber; i++) {
            List<TestSanMen> list = new ArrayList<>();
			// 进入正题,随机选择一扇门 1-3 
            int random = new Random().nextInt(3)+1;
			// 然后在这道门后面放入劳斯莱斯汽车  门牌号,车
            TestSanMen car = new TestSanMen(random,true);
			// 剔除车所属的门牌号,再选择一个门牌号
            int sheep_one_random = random != 1 ? 
            1 : random != 2 ? 
            2 : random != 3 ? 
            3 : 0;
			// 放入羊                              门牌号            羊
            TestSanMen sheep_one = new TestSanMen(sheep_one_random,false);
			// 再剔除前面两个门牌号
            int sheep_two_random = random + sheep_one_random == 3 ?
             3 : random + sheep_one_random == 4 ? 
             2 : random + sheep_one_random == 5 ? 
             1 : 0;
			// 放入羊                                   门牌号        羊      
            TestSanMen sheep_two = new TestSanMen(sheep_two_random,false);
			//加入到集合里面去
            list.add(car);
            list.add(sheep_one);
            list.add(sheep_two);
			//      次数 ,每次的情况集合
            map.put(i,list);
        }
		// 作者的求证方式是第二次选择每次我都去选择换一扇门,
		// 不遵循第一次的选择,看它后面为车的概率是否是2/3,finalCount为得车的次数
        int finalCount = 0;
		// 循环所有情况
        for (Map.Entry<Integer,List<TestSanMen>> item : map.entrySet()) {
			// 主持人让你第一次选择一扇门
            int random = new Random().nextInt(3)+1;
			// 然后把这扇门取出来                     stream流 java1.8新特性
            TestSanMen chooseDoor = item.getValue().stream()
            .filter(i->i.getDoorNumber()==random).findAny().orElse(null);

			// 得到这扇门的门牌号
            int choose_Door_Number = chooseDoor.getDoorNumber();
            System.out.println(choose_Door_Number);

            // 主持人再取出剩下两扇门中一扇为羊的门
            TestSanMen noChooseDoor_one = item.getValue().stream()
            .filter(i->i.getFlag()==false&&i.getDoorNumber()!=random)
            .limit(1).findAny().orElse(null);

         	// 得到这扇门的门牌号
            int noChooseDoor_One_Number = noChooseDoor_one.getDoorNumber();

            System.out.println(noChooseDoor_One_Number);
			//然后剔除前面两扇门,得到最终的门牌号,也就是换的那扇门
            int finalNumber = choose_Door_Number + noChooseDoor_One_Number == 3 ? 
            3 : choose_Door_Number + noChooseDoor_One_Number == 4 ? 
            2 : choose_Door_Number + noChooseDoor_One_Number == 5 ? 
            1 : 0;
			//然后把这扇门取出来
            TestSanMen finalObject = item.getValue().stream()
            .filter(i -> i.getDoorNumber() == finalNumber).findAny().orElse(null);
			// 判断这扇门后面是否为车
            if (finalObject.getFlag() == true) {
                finalCount++; //为车的次数
            }
        }
										为车的次数/总次数*100 得到概率
        System.out.println("概率为:"+(finalCount/sunNumber*100)+"%");

    }

}

程序运行结果:

“三门问题”:数学经典概率问题,用java代码求证_第2张图片
结果确实为2/3。

在作者写完代码后理解了结果为什么为2/3,作者假设重新选择(第二次选择)时每次都换一扇门,只要第一次选择不为车,反过来理解,第一次选择只要为羊,那么在主持人打开一扇为羊的门时,换一扇门必定得车,也就是换另外一道门的概率就为第一次选择三道门中为羊的概率,2/3。

你可能感兴趣的:(java)