题目是这样的:
有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后,主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门,现在主持人问你,要不要换个门,请问你换还是不换?
起初我以为换与不换都是二分之一的机率,后来,我写了一个程序来证实,发现还是要换的,换是三分之二的中奖机率,不换是三分之一的中奖机率,差很多。
直接看我的测试结果吧:
这是C语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)
这是C#语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)
这是Java语言编写的程序,测试的结果。(要解答这个题目,其实和什么编程语言无关)
多次测试的结果显示,如果换门的话选中目标门的机率大多了。
当然,采样20次,有点少,那我们就来进行1000次测试,看看结果又如何。
当测试1000次时,就可以明显的发现,不换门的中奖机率是3/1,而换门的中奖机率是3/2,差别很大。
以下是C、C#、Java三种不同语言编写的测试代码:
一、C语言测试代码
1 #include2 #include 3 #include 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
二、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#include #include //有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后//主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门//现在主持人问你,要不要换个门,请问你换还是不换?////测试(总次数, 换门)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
实践出真理,欢迎大家批评指正。