引言

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

《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. 在距离distribution 证书过期一个月(或被手动revoke了)的时候会受到apple的邮件

    ​ ​编辑 虽然distribution过期(或者被手动revoke)了,如果你的开发者账号是company(公司)类型或个人类型的,只要你的每年99$的开发者membership没有过期,就不会对已 ...

  2. Jenkins Blue Ocean

    介绍 Blue Ocean 是 pipeline 的可视化UI.同时兼容经典的自由模式的 job.Jenkins Pipeline 从头开始设计,但仍与自由式作业兼容,Blue Ocean 减少了经典 ...

  3. WebRTC SDP 详解和剖析

    WebRTC 是 Web Real-Time Communication,即网页实时通信的缩写,是 RTC 协议的一种 Web 实现,项目由 Google 开源,并和 IETF 和 W3C 制定了行业 ...

  4. Codeforce 318A - Even Odds(数学水题)

    Being a nonconformist, Volodya is displeased with the current state of things, particularly with the ...

  5. Educational Codeforces Round 93 (Rated for Div. 2)

    Educational Codeforces Round 93 (Rated for Div. 2) A. Bad Triangle input 3 7 4 6 11 11 15 18 20 4 10 ...

  6. AtCoder Beginner Contest 178 个人题解(C组合问题 + 快速幂,D规律,E数学公式变形)

    补题链接:Here A - Not Editorial 给出 \(x = 1\) 则输出 0:给出 \(x = 0\) 则输出 1 利用 x ^ 1 可以快速实现 \(x\) 的转换 B - Prod ...

  7. mysql 使用 trim去不掉空格 解决

    使用mysql8.0时 发现 有几个空字符串怎么也过滤不掉,使用 is not null.trim()<>''.length()>=1都不行,最后查了一些资料说 trim只能去除半角 ...

  8. Zookeeper(3)---java客户端的使用

    前面介绍了zk指令的使用,这里说一下java客户端中怎么使用这些指令 <dependency> <groupId>org.apache.zookeeper</groupI ...

  9. node-sass安装失败问题

    在node 中安装sass依赖总会出现各种各样的问题,第一次遇见这样的问题 Cached binary found at C:\Users\ltzhouhuan\AppData\Roaming\npm ...

  10. vue-cli 3.x 项目,如何增加对 jsx 的支持?vue-cli 3.x 项目,如何增加对 jsx 的支持?

    https://segmentfault.com/q/1010000019655500