引言

《双色球头奖概率与被雷劈中的概率哪个高?》

《3人轮流射击,枪法最差的反而更容易活下来?》

让我们用Java来探索ta们!

悖论1:著名的三门问题

规则描述:你正在参加一个游戏节目,你被要求在三扇门中选择一扇:其中一扇后面有一辆车;其余两扇后面则是山羊。你选择了一道门,假设是一号门,然后知道门后面有什么的主持人,开启了另一扇后面有山羊的门,假设是三号门。他然后问你:“你想选择二号门吗?请问若想获得车,参赛者应该换二号门吗?

论证:分析需求,拆解为如下代码

/**
* <p> 三门问题解决方案 </p>
* @author yuanfeng.wang
* @since 2023/8/29
*/
import java.util.Random; public class ThreeDoorSolution { public static void main(String[] args) {
// 模拟执行1万次,打印获胜的概率
threeDoor(10000);
} /**
* 三门问题逻辑拆解
* @param numSimulations 总共执行多少轮游戏
*/
private static void threeDoor(int numSimulations) {
int switchWins = 0;
int stayWins = 0; Random random = new Random();
for (int i = 0; i < numSimulations; i++) {
// 随机确定车所在的门
int carDoor = random.nextInt(3); // 玩家随机选择一扇门
int playerChoice = random.nextInt(3); // 主持人随机打开一扇门:要求该门不是玩家选择的,且必须是羊
int openedDoor;
do {
openedDoor = random.nextInt(3);
} while (openedDoor == carDoor || openedDoor == playerChoice); // 换门后的选择:不能是打开的门,不能是玩家选择的门,则是交换之后的门
int finalChoice;
do {
finalChoice = random.nextInt(3);
} while (finalChoice == playerChoice || finalChoice == openedDoor); // 计算是否换门获胜
if (finalChoice == carDoor) {
switchWins++;
} // 计算不换门获胜
if (playerChoice == carDoor) {
stayWins++;
}
} // 输出结果
System.out.println("在 " + numSimulations + " 次模拟中:");
System.out.println("换门获胜的概率:" + (double) switchWins / numSimulations);
System.out.println("不换门获胜的概率:" + (double) stayWins / numSimulations);
}
}
// 模拟运行,打印结果如下
// 在 10000 次模拟中:
// 换门获胜的概率:0.6679
// 不换门获胜的概率:0.3321

结论:三门问题看似一道简单的概率题,几十年来却一直引发巨大争议,持两种不同观点的人基本是五五开;事实上始终选择换门的玩家,获胜的概率2/3,而保持原方案的胜率只有1/3

悖论2:双色球我能中大奖

规则描述:从1-33个红色球中随机选出6个,再从1-16个蓝色球中随机选择1个,最终开奖出一注 6+1组合球,无顺序要求;

  • 一等奖:中6红 + 1蓝
  • 二等奖:中6红
  • 三等奖:中5红 + 1蓝
  • 四等奖:中4红 + 1蓝,或只中5个红
  • 五等奖:中3红 + 1蓝,或只中4个红
  • 六等奖:中1蓝

论证:分析玩法,计算一等奖中奖率,从33个红球样本中选择6个,计算总共的组合数,即数学公式C(n, m) = n!/((n-m)! * m!),代入计算C(33, 6) = 33!/((33-6)! * 6!) = 1107568,再乘以16,最终得出一等奖获奖概率1/17721088。

分析规则,以下代码展示了开奖一次,购买N注时,打印中奖信息的程序,当代入N=500万时,多次执行,可以很轻松打印出一等奖


import java.util.*; /**
* <p>双色球随机模拟</p>
* @author yuanfeng.wang
* @since 2023/8/29
*/
public class SsqSolution { private static Random random = new Random(); /**
* 开奖的红球
*/
private static Set<Integer> winningRedBalls; /**
* 开奖的蓝球
*/
private static int winningBlueBall; // 静态块初始化一组开奖号码
static {
// 篮球 01-16
winningBlueBall = random.nextInt(16) + 1; // 红球 01-33生成6个
winningRedBalls = new HashSet<>();
while (winningRedBalls.size() < 6) {
int num = random.nextInt(33) + 1;
winningRedBalls.add(num);
}
} public static void main(String[] args) {
play(500_0000);
} /**
*
* @param num 运行一次程序只开一次奖,此参数表示总共购买多少注
*/
public static void play(int num) {
System.out.println("\n本期开奖号码:");
System.out.println("红球:" + winningRedBalls + " 篮球:" + winningBlueBall);
for (int i = 0; i < num; i++) {
playOnce();
}
} private static void playOnce() {
Set<Integer> userRedBalls = getUserSelectedRedBalls();
int userBlueBall = getUserSelectedBlueBall(); int redBallMatch = countMatchingBalls(userRedBalls, winningRedBalls);
boolean blueBallMatch = (userBlueBall == winningBlueBall); if (redBallMatch == 6 && blueBallMatch) {
System.out.println("\n恭喜你中了一等奖!");
System.out.println("玩家购买的号码:");
System.out.println("红球:" + userRedBalls + " 蓝球:" + userBlueBall);
} else if (redBallMatch == 6) {
System.out.println("\n恭喜你中了二等奖!");
} else if (redBallMatch == 5 && blueBallMatch) {
// System.out.println("\n恭喜你中了三等奖!");
} else if (redBallMatch == 5 || (redBallMatch == 4 && blueBallMatch)) {
// System.out.println("\n恭喜你中了四等奖!");
} else if (redBallMatch == 4 || (redBallMatch == 3 && blueBallMatch)) {
// System.out.println("\n恭喜你中了五等奖!");
} else if (blueBallMatch) {
// System.out.println("\n恭喜你中了最小奖!");
} else {
//没中奖,不打印记录
}
} /**
* 返回玩家选择的6个红球,范围1-33,不重复
*/
private static Set<Integer> getUserSelectedRedBalls() {
Set<Integer> userRedBalls = new HashSet<>();
while (userRedBalls.size() < 6) {
int num = random.nextInt(33) + 1;
userRedBalls.add(num);
}
return userRedBalls;
} /**
* 玩家选择的1个蓝球,范围1-16
*/
private static int getUserSelectedBlueBall() {
return random.nextInt(16) + 1;
} /**
* 匹配中了几个红球
* @return 中红球个数
*/
private static int countMatchingBalls(Set<Integer> userBalls, Set<Integer> winningBalls) {
int count = 0;
for (int ball : userBalls) {
if (winningBalls.contains(ball)) {
count++;
}
}
return count;
} }

结论:排除其它因素,头奖概率约1700万分之1,这个结论并不直观,例举如下几个进行对比

1.一家祖孙三代人的生日都在同一天的概率约为27万分之一

2.小行星撞击地球的概率保守推测是200万分之一

3.生出全男或全女四胞胎的概率约为352万分之一

悖论3:三个枪手

描述:三个小伙子同时爱上了一个姑娘,为了决定他们谁能娶这个姑娘,他们决定用枪进行一次决斗。A的命中率是30%,B比他好些,命中率是50%,最出色的枪手是C,他从不失误,命中率是100%。由于这个显而易见的事实,为公平起见,他们决定按这样的顺序:A先开枪,B第二,C最后。然后这样循环,直到他们只剩下一个人。那么A第一枪应该怎么打?谁活下来的概率最大?

论证:每个人的目标都是活下来,为了目标寻找最好的策略。以下开始分人讨论

A:

  • 若A开枪射杀了B,则下个开枪是C,C会100%射杀A,这不是一个好策略
  • 若A开枪射杀了C,则下一轮B会有50%的几率杀掉自己
  • 若A开枪未打中,则下一轮可以坐山观虎斗,所以A最好的策略看似是故意打空枪更好一些

B:

  • 若A已经将C射杀,此时B与A互相射击,B的生存率高于A
  • B只能选择射杀C,因为只要C活着,都会优先射杀B

C:

  • 先消除威胁大的B,然后再杀掉A,只要自己有开2枪的机会,直接获胜

结论:需求太复杂,暂未实现生存概率计算,欢迎补充悖论3的代码论证过程

作者:京东保险 王苑沣

来源:京东云开发者社区 转载请注明来源

买彩票能中大奖?用Java盘点常见的概率悖论 | 京东云技术团队的更多相关文章

  1. springboot升级过程中踩坑定位分析记录 | 京东云技术团队

    作者:京东零售 李文龙 1.背景 " 俗话说:为了修复一个小bug而引入了一个更大bug " 因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的 ...

  2. 红黑树深入剖析及Java实现(转自知乎美团点评技术团队)

    作者:美团点评技术团队 链接:https://zhuanlan.zhihu.com/p/24367771 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 红黑树是平衡 ...

  3. 大型情感剧集Selenium:6_selenium中的免密登陆与cookie操作【华为云技术分享】

    网站登录 现在各大平台在反爬虫功能上,可谓花样繁多.总结下来按照破解成功率排名,最高的是滑动解锁.其次是验证码数字.之后是一次点击对应的汉字,最后是想12306之前那种反人类的让你说那些是奶糖吧,哈哈 ...

  4. 从单个系统到云翼一体化支撑,京东云DevOps推进中的一波三折

    作者:王利莹 采访嘉宾:京东云DevOps团队负责人 郑永宽 今年,IDC 特别针对中国地区发布了<IDC MarketScape:中国 DevOps 云市场2019,厂商评估>研究报告, ...

  5. ZT 打工者买彩票中1000万 5年后变逃犯身上剩80元

    打工者买彩票中1000万 5年后变逃犯身上剩80元   2014-01-07 08:22 来源:都市快报 我有话说 挥霍—— 从800万到80元 在湖南永州零陵区富家桥镇茶叶湾村,陈某是不折不扣的名人 ...

  6. Java实现 蓝桥杯VIP 算法提高 阮小二买彩票

    算法提高 阮小二买彩票 时间限制:1.0s 内存限制:512.0MB 问题描述 在同学们的帮助下,阮小二是变的越来越懒了,连算账都不愿意自己亲自动手了,每天的工作就是坐在电脑前看自己的银行账户的钱是否 ...

  7. java数组实现买彩票(通过标识符进行判断的思想)

    package com.wh.shuzu; import java.util.Random; import java.util.Scanner; /** * 买彩票 * @author 王拥江同学 * ...

  8. java数组实现买彩票(重复则重新遍历查询思想)

    package com.wh.shuzu; import java.util.Arrays; /** * 买彩票 * @author 丁璐同学 * 重复则重新遍历查询思想 */ public clas ...

  9. java数组实现买彩票(平移覆盖思想)

    package com.wh.shuzu; /** * 买彩票 * @author 贾相如同学 * 平移覆盖思想 */ public class Lotery3 { public static voi ...

  10. 如何在tomcat中如何部署java EE项目

    如何在tomcat中如何部署java EE项目 1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法,也是初学者最常用的方法.2.在tomcat安 ...

随机推荐

  1. 深度解读鸿蒙轻内核CPU占用率

    摘要:CPUP(Central Processing Unit Percentage,CPU占用率)分为系统CPU占用率和任务CPU占用率.用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规 ...

  2. 湖仓一体天花板,大数据一站式SQL分析技术实践

    摘要:本文将详细阐述HetuEngine在实现一站式SQL分析所面临的挑战.技术架构和案例. 本文分享自华为云社区<[华为云Stack][大架光临]第7期:湖仓一体天花板,大数据一站式SQL分析 ...

  3. 火山引擎云原生数据仓库 ByteHouse 技术白皮书 V1.0 (Ⅵ)

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近日,<火山引擎云原生数据仓库 ByteHouse 技术白皮书>正式发布.白皮书简述了 ByteHou ...

  4. Mac Parallels (PD) 常规设置

    Mac 上安装了 Parallels (PD) 程序默认使用 Parallels 打开,比较烦人,取消设置: 虚机中不显示 mac 的菜单栏 ,按 Control + Option 就会临时显示 备份 ...

  5. SpringBoot Docker 发布到 阿里仓库

    1. 创建仓库 管理里面,可以查看详细的信息 设置登录密码 2. 接下来,将本地镜像推到阿里 : SpringBoot Docker 发布 docker commit 这部分可以不操作 docker ...

  6. Spring Boot 整合 Camunda 实现工作流

    工作流是我们开发企业应用几乎必备的一项功能,工作流引擎发展至今已经有非常多的产品.最近正好在接触Camunda,所以来做个简单的入门整合介绍.如果您也刚好在调研或者刚开始计划接入,希望本文对您有所帮助 ...

  7. 国内pip源提示“not a trusted or secure host”解决方案

    大家应该都知道怎么添加国内pip源(主要是豆瓣和阿里云),~/.pip/pip.conf文件配置大概如下(下面注释掉了豆瓣源): [global] # index-url = http://pypi. ...

  8. Sentinel 是如何做限流的

    限流是保障服务高可用的方式之一,尤其是在微服务架构中,对接口或资源进行限流可以有效地保障服务的可用性和稳定性. 之前的项目中使用的限流措施主要是Guava的RateLimiter.RateLimite ...

  9. C#利用控件实现柱形图分析

    数据 { using (SqlConnection con = new SqlConnection("server=.;uid=sa;pwd=;database=db_TomeOne&quo ...

  10. nginx 负载均衡 proxy_pass 与 upstream 及 rewrite ,expires 的配置总结

    本文为博主原创,转载请注明出处: 先查看 一段 nginx 相关的配置: location /test/   {   set $arg_remote_addr $request_id; proxy_p ...