题目是这样的:
有三扇门,其中一扇门里有奖品,三选一,你选择其中一扇门之后,主持人先不揭晓答案,而是从另外两扇门中排除掉一个没有奖品的门,现在主持人问你,要不要换个门,请问你换还是不换?
起初我以为换与不换都是二分之一的机率,后来,我写了一个程序来证实,发现还是要换的,换是三分之二的中奖机率,不换是三分之一的中奖机率,差很多。
直接看我的测试结果吧:
这是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); }
实践出真理,欢迎大家批评指正。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)