引言
《双色球头奖概率与被雷劈中的概率哪个高?》
《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的代码论证过程
作者:京东保险 王苑沣
起源:京东云开发者社区 转载请注明起源