首页 > 技术文章 > 思考:有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后,主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门,现在主持人问你,要不要换个门,请问你换还是不换?

zhouyou96 2015-07-02 15:24 原文

题目是这样的:

有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后,主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门,现在主持人问你,要不要换个门,请问你换还是不换?

起初我以为换与不换都是二分之一的机率,后来,我写了一个程序来证实,发现还是要换的,换是三分之二的中奖机率,不换是三分之一的中奖机率,差很多。

 

直接看我的测试结果吧:

这是C语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)

 

这是C#语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)

 

这是Java语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)

 

多次测试的结果显示,如果换门的话选中目标门的机率大多了。

当然,采样20次,有点少,那我们就来进行1000次测试,看看结果又如何。

当测试1000次时,就可以明显的发现,不换门的中奖机率是3/1,而换门的中奖机率是3/2,差别很大。

 

以下是C、C#、Java三种不同语言编写的测试代码:

 

一、C语言测试代码

  1 #include <stdio.h>
  2 #include <time.h>
  3 #include <stdlib.h>
  4 
  5 //有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后
  6 //主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门
  7 //现在主持人问你,要不要换个门,请问你换还是不换?
  8  9 
 10 //测试(总次数, 换门)
 11 void test(int max, int change);
 12 
 13 //入口函数
 14 void main()
 15 {
 16     //各自测试的次数
 17     int count = 20;
 18 
 19     //初始化随机种子
 20     srand((unsigned)time(NULL));
 21 
 22     //不换门测试
 23     printf("不换门测试:\n");
 24     test(count, 0);
 25 
 26     //换门测试
 27     printf("换门测试:\n");
 28     test(count, 1);
 29 }
 30 
 31 //测试(总次数, 换门)
 32 void test(int max, int change)
 33 {
 34 
 35     //max    次数:测试的总次数
 36     //change 换门: 0不换  1换门
 37 
 38     int i;        //循环因子
 39     int m;        //目标:本次中奖的目标数字
 40     int c;        //初选:本次选手初次选择的数字
 41     int x;        //选择:本次选手最终选择的数字
 42     int p;        //排除:主持人排除掉没奖的数字
 43     int z = 0;    //中奖:中奖的总次数
 44 
 45     //循环多次模拟换门测试
 46     for (i=0; i<max; i++)
 47     {
 48         m = rand()%3; //目标:本次中奖的目标数字
 49         c = rand()%3; //初选:本次选手初次选择的数字
 50         
 51         //求出主持人要排除的数字
 52         if(m==c)
 53         {
 54             //选手选择了一个有奖品的,主持人从另外两个没奖品当中随机排除掉一下
 55             p = rand()%2;  //产生  false or true
 56             switch(c)
 57             {
 58             case 0:  //要排除的是:2 or 1
 59                 p = p?2:1;
 60                 break;
 61             case 1:  //要排除的是:2 or 0
 62                 p = p?2:0;
 63                 break;
 64             case 2:  //要排除的是:1 or 0
 65                 p = p?1:0;
 66                 break;;
 67             }
 68         }
 69         else
 70         {
 71             //选手选择了一个没奖品的,主持人排除另一个没奖品的
 72             //3-(m+c) = p
 73             //3-(0+1) = 2
 74             //3-(0+2) = 1
 75             //3-(1+2) = 0
 76             p = 3-(m+c);            
 77         }
 78         
 79         //决定终选
 80         if(change)
 81         {//换门
 82             //x=3-(p+c)
 83             //x=3-(0+1) = 2
 84             //x=3-(0+2) = 1
 85             //x=3-(1+2) = 0
 86             x = 3-(p+c);  //换个门
 87         }
 88         else
 89         {//不换门
 90             x = c;  //最终选择和初次选择一样
 91         }
 92         
 93         //结果
 94         printf("第%02d次  初选的是:%d, 目标是:%d, 排除的是:%d, 终选的是:%d", i+1, c, m, p, x);
 95         if(m==x)
 96         {
 97             //中奖了
 98             z++;
 99             printf("  (中奖了)\n");
100         }
101         else
102         {
103             //没中奖
104             printf("\n");
105         }
106     }
107     //输出结果
108     printf("进行%d次测试,中奖%d次。\n\n", max, z);
109 }

 

二、C# 测试代码

using System;
using System.Collections.Generic;
using System.Text;

//有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后
//主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门
//现在主持人问你,要不要换个门,请问你换还是不换?
//

namespace Test123
{
    class Program
    {
        //初始化随机数生成器
        static Random random = new Random();

        //入口函数
        static void Main(string[] args)
        {
            //测试总次数
            int count = 20;
            //不换门测试
            Console.WriteLine("不换门测试:");
            test(count, false);
            //换门测试
            Console.WriteLine("换门测试:");
            test(count, true);
        }

        //测试(总次数, 换门)
        static void test(int max, bool change)
        {
            //max    次数:测试的总次数
            //change 换门: 0不换  1换门

            int i;        //循环因子
            int m;        //目标:本次中奖的目标数字
            int c;        //初选:本次选手初次选择的数字
            int x;        //选择:本次选手最终选择的数字
            int p = 0;    //排除:主持人排除掉没奖的数字
            int z = 0;    //中奖:中奖的总次数
            bool b;       //临时布尔类型变量

            //循环多次模拟换门测试
            z = 0; //重置中奖次数
            for (i = 0; i < max; i++)
            {
                m = random.Next(3); //目标:本次中奖的目标数字
                c = random.Next(3); //初选:本次选手初次选择的数字

                //求出主持人要排除的数字
                if (m == c)
                {
                    //选手选择了一个有奖品的,主持人从另外两个没奖品当中随机排除掉一下
                    b = random.Next(2) == 1;  //产生  false or true
                    switch (c)
                    {
                        case 0:  //要排除的是:2 or 1
                            p = b ? 2 : 1;
                            break;
                        case 1:  //要排除的是:2 or 0
                            p = b ? 2 : 0;
                            break;
                        case 2:  //要排除的是:1 or 0
                            p = b ? 1 : 0;
                            break;
                    }
                }
                else
                {
                    //选手选择了一个没奖品的,主持人排除另一个没奖品的
                    //3-(m+c) = p
                    //3-(0+1) = 2
                    //3-(0+2) = 1
                    //3-(1+2) = 0
                    p = 3 - (m + c);
                }

                //决定终选
                if (change)
                {//换门
                    //x=3 - (p + c)
                    //x=3 - (0 + 1) = 2
                    //x=3 - (0 + 2) = 1
                    //x=3 - (1 + 2) = 0
                    x = 3 - (p + c);  //换个门
                }
                else
                {//不换门
                    x = c;  //最终选择和初次选择一样
                }

                //结果
                Console.Write("第{0:00}次  初选的是:{1}, 目标是:{2}, 排除的是:{3}, 终选的是:{4}", i + 1, c, m, p, x);
                if (m == x)
                {
                    //中奖了
                    z++;
                    Console.Write("  (中奖了)\n");
                }
                else
                {
                    //没中奖
                    Console.Write("\n");
                }
            }
            //输出结果
            Console.Write("进行{0}次测试,中奖{1}次。\n\n\n", max, z);
        }


    }
}

 

三、Java 测试代码

package com.huarui.test;

//有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后
//主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门
//现在主持人问你,要不要换个门,请问你换还是不换?
//
public class Test {
    
    public static void main(String[] args){
        
        //测试的总次数
        int count = 20;
        //不换门测试
        System.out.println("不换门测试:");
        test(count, false);
        //换门测试
        System.out.println("换门测试:");
        test(count, true);
        
    }
    
    //测试(总次数, 换门)
    static void test(int max, boolean change)
    {
        //max    次数:测试的总次数
        //change 换门: 0不换  1换门

        int i;        //循环因子
        int m;        //目标:本次中奖的目标数字
        int c;        //初选:本次选手初次选择的数字
        int x;        //选择:本次选手最终选择的数字
        int p = 0;    //排除:主持人排除掉没奖的数字
        int z = 0;    //中奖:中奖的总次数

        //循环多次模拟换门测试
        z = 0; //重置中奖次数
        for (i = 0; i < max; i++)
        {
            m = (int)(Math.random()*3); //目标:本次中奖的目标数字
            c = (int)(Math.random()*3); //初选:本次选手初次选择的数字

            //求出主持人要排除的数字
            if (m == c)
            {
                //选手选择了一个有奖品的,主持人从另外两个没奖品当中随机排除掉一下
                boolean b =  (int)(Math.random()*2) == 1;  //产生  false or true
                switch (c)
                {
                    case 0:  //要排除的是:2 or 1
                        p = b ? 2 : 1;
                        break;
                    case 1:  //要排除的是:2 or 0
                        p = b ? 2 : 0;
                        break;
                    case 2:  //要排除的是:1 or 0
                        p = b ? 1 : 0;
                        break;
                }
            }
            else
            {
                //选手选择了一个没奖品的,主持人排除另一个没奖品的
                //3-(m+c) = p
                //3-(0+1) = 2
                //3-(0+2) = 1
                //3-(1+2) = 0
                p = 3 - (m + c);
            }

            //决定终选
            if (change)
            {//换门
                //x=3 - (p + c)
                //x=3 - (0 + 1) = 2
                //x=3 - (0 + 2) = 1
                //x=3 - (1 + 2) = 0
                x = 3 - (p + c);  //换个门
            }
            else
            {//不换门
                x = c;  //最终选择和初次选择一样
            }

            //结果
            //, i + 1, c, m, p, x
            
            System.out.format("第%02d次  初选的是:%d, 目标是:%d, 排除的是:%d, 终选的是:%d", i + 1, c, m, p, x);
            if (m == x)
            {
                //中奖了
                z++;
                System.out.print("  (中奖了)\n");
            }
            else
            {
                //没中奖
                System.out.print("\n");
            }
        }
        //输出结果
        System.out.format("进行%d次测试,中奖%d次。\n\n\n", max, z);
    }
}

 

四、另外,当需要进行1000次测试时,就不适合将每一次测试的结果都进行输出了,代码稍微改一下,将C语言的代码发给大家看看

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

//有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后
//主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门
//现在主持人问你,要不要换个门,请问你换还是不换?
////测试(总次数, 换门)
void test(int max, int change);

//入口函数
void main()
{
    //各自测试的次数
    int i, count = 1000;

    //初始化随机种子
    srand((unsigned)time(NULL));

    for(i=0;i<5;i++)
    {
        printf("================================\n");

        //不换门测试
        printf("不换门测试:\n");
        test(count, 0);

        //换门测试
        printf("换门测试:\n");
        test(count, 1);
    }
}

//测试(总次数, 换门)
void test(int max, int change)
{

    //max    次数:测试的总次数
    //change 换门: 0不换  1换门

    int i;        //循环因子
    int m;        //目标:本次中奖的目标数字
    int c;        //初选:本次选手初次选择的数字
    int x;        //选择:本次选手最终选择的数字
    int p;        //排除:主持人排除掉没奖的数字
    int z = 0;    //中奖:中奖的总次数

    //循环多次模拟换门测试
    for (i=0; i<max; i++)
    {
        m = rand()%3; //目标:本次中奖的目标数字
        c = rand()%3; //初选:本次选手初次选择的数字
        
        //求出主持人要排除的数字
        if(m==c)
        {
            //选手选择了一个有奖品的,主持人从另外两个没奖品当中随机排除掉一下
            p = rand()%2;  //产生  false or true
            switch(c)
            {
            case 0:  //要排除的是:2 or 1
                p = p?2:1;
                break;
            case 1:  //要排除的是:2 or 0
                p = p?2:0;
                break;
            case 2:  //要排除的是:1 or 0
                p = p?1:0;
                break;;
            }
        }
        else
        {
            //选手选择了一个没奖品的,主持人排除另一个没奖品的
            //3-(m+c) = p
            //3-(0+1) = 2
            //3-(0+2) = 1
            //3-(1+2) = 0
            p = 3-(m+c);            
        }
        
        //决定终选
        if(change)
        {//换门
            //x=3-(p+c)
            //x=3-(0+1) = 2
            //x=3-(0+2) = 1
            //x=3-(1+2) = 0
            x = 3-(p+c);  //换个门
        }
        else
        {//不换门
            x = c;  //最终选择和初次选择一样
        }
        
        //结果
        //printf("第%02d次  初选的是:%d, 目标是:%d, 排除的是:%d, 终选的是:%d", i+1, c, m, p, x);
        if(m==x)
        {
            //中奖了
            z++;
            //printf("  (中奖了)\n");
        }
        else
        {
            //没中奖
            //printf("\n");
        }
    }
    //输出结果
    printf("进行%d次测试,中奖%d次。\n\n", max, z);
}

 

实践出真理,欢迎大家批评指正。 

 

 

推荐阅读