从《三门问题》出发,编写出的《N门问题》的java程序代码

package test1;

import java.util.Random;

//  《三门问题》和《六门问题》的升级版   =>> 《N门问题》java程序
public class MontyHallProblemEnhanced {
    
    // 设置门的数量,即为:《NUM_ALL_DOORS门问题》
    public static final int NUM_ALL_DOORS = 6 ; 
    
    // 设置总共有NUM_ALL_WINNING_DOORS扇门里有奖, 这个值的设定要满足:0 < NUM_ALL_WINNING_DOORS < NUM_ALL_DOORS 这个条件
    public static final int NUM_ALL_WINNING_DOORS = 1 ; 
    
    // 设置一开始时,嘉宾可以选择的门的数量,这个值的设定要满足:0 < NUM_ALL_CHOSEN_DOORS < NUM_ALL_DOORS 这个条件
    public static final int NUM_ALL_CHOSEN_DOORS = 1 ; 
    
    // 设置要主持人可以先开启的门的数量,这个值的设定要满足:0 < NUM_ALL_OPENED_DOORS < NUM_ALL_DOORS - NUM_ALL_WINNING_DOORS - NUM_ALL_CHOSEN_DOORS 这个条件
    public static final int NUM_ALL_OPENED_DOORS = 3 ; 
    
    // 设置要丢弃已选中的NUM_ALL_CHOSEN_DOORS扇门中的 NUM_ALL_DISCARDED_DOORS 扇门,这个值的设定要满足:0 < NUM_ALL_DISCARDED_DOORS <= NUM_ALL_CHOSEN_DOORS 这个条件
    public static final int NUM_ALL_DISCARDED_DOORS = 1 ;
    
    // 设置可以重新选择的门的数量,这个值的设定要满足: 0 < NUM_ALL_REPICKED_DOORS < NUM_ALL_DOORS - NUM_ALL_CHOSEN_DOORS - NUM_ALL_OPENED_DOORS 这个条件
    public static final int NUM_ALL_REPICKED_DOORS = 1 ; 
    
    // 设置总共要获得 NUM_ALL_WINNING_DOORS 里的 NUM_ALL_GET_WINNING_DOORS 个门才能拿到大奖 ,这个值的设定要满足: 0 < NUM_ALL_GET_WINNING_DOORS <= NUM_ALL_WINNING_DOORS
    public static final int NUM_ALL_GET_WINNING_DOORS = 1 ; 
    
    // 设置测试的次数,显示 TEST_TIMES次的结果概率。
    public static final int TEST_TIMES = 10 ;  
    
    // 设置每次测试的结果,都是经过 NUM_ITERATIONS 次循环游戏的结果。
    public static final int NUM_ITERATIONS = 1000000; 
    
    // 主程序开始运行
    public static void main(String[] args) {
        // 现在开始计时
        long startTime = System.currentTimeMillis();
        
        System.out.println("\t程序的说明:这个程序所代表的是《N门问题》,调节初始的参数,就可以有非常多种的玩法,而且可以算出每一种不同玩法  >> 中大奖和不中大奖的概率。" + 
                             "\n这里测试的是《六门问题》,初始参数的设置,是在这个程序的最上端有说明。游戏是这样的:一开始,嘉宾先选中任意一扇门,接着,"
                                + "\n主持人打开其余三扇没有大奖的门,再问嘉宾要不要换门?程序结果输出是:嘉宾选择换门和选择不换门,分别获得大奖的概率。"
                                   + "\n总共输出TEST_TIMES次结果,每一次的结果都是经过NUM_ITERATIONS次循环模拟游戏得出的大数测试概率\n"
                                    + " ***********************************************************************************************************************************************  \n");
        // 现在开始游戏
        for(int i = 0 ; i < TEST_TIMES ; i++){  // 进行TEST_TIMES次大数模拟游戏测试,进行TEST_TIMES次的结果输出
            
            int stayDoorsWins = 0;   // 嘉宾选择不换门获得大奖的次数
            int switchDoorsWins = 0; // 嘉宾选择换门之后获得大奖次数
            
            Random random = new Random();
            for (int j = 0; j < NUM_ITERATIONS; j++) {  // 每一次输出的结果,都是进行NUM_ITERATIONS次循环游戏后得出的结果
                
                int[] allDoors = new int[NUM_ALL_DOORS]; // 整个allDoors整数数组的初始化默认值全部都为 0
                
                // 第一步:随机生成 NUM_ALL_WINNING_DOORS 个有奖的门的编号
                int[] allWinningDoors = new int[NUM_ALL_WINNING_DOORS];
                for(int m = 0; m < NUM_ALL_WINNING_DOORS; m++){
                    do {
                        allWinningDoors[m] = random.nextInt(NUM_ALL_DOORS);
                    } while ( allDoors[allWinningDoors[m]] == 1);  // 排除掉已经生成的有奖的门的条件
                    allDoors[allWinningDoors[m]] = 1 ;  // 把随机生成的 NUM_ALL_WINNING_DOORS扇有奖的门的编号所对应的allDoors整数数组的默认值 从 0 变为 1 ,为后续的程序的编写和运行做准备
                }
                
                // 第二步:嘉宾一开始时随机选到的那NUM_ALL_CHOSEN_DOORS扇门的编号
                int[] allChosenDoors = new int[NUM_ALL_CHOSEN_DOORS];
                for(int n = 0; n < NUM_ALL_CHOSEN_DOORS; n++){
                    do {
                        allChosenDoors[n] = random.nextInt(NUM_ALL_DOORS);
                    } while ( allDoors[allChosenDoors[n]] == 2 || allDoors[allChosenDoors[n]] == 3); // 排除掉嘉宾已经选好的门
                    /**接下来,把嘉宾随机选到的那NUM_ALL_CHOSEN_DOORS扇门的编号所对应的整数数组的值改变  >> 有可能选中的是空门,也有可能选中的是有奖的门:
                     * 如果选到的是空门, 则要把这个门的 编号所对应的整数数组的默认值从0 变为2 ;而如果选到的是有奖的门,而且是没有被嘉宾选过的门,
                     * 则把这个门的编号所对应的整数数组的值从1变为3 ,这个也是为后续的程序的编写和运行做准备 */
                    if(allDoors[allChosenDoors[n]] == 0){
                        allDoors[allChosenDoors[n]] = 2 ; 
                    }else if(allDoors[allChosenDoors[n]] == 1){
                        allDoors[allChosenDoors[n]] = 3 ;
                    }
                }
                
                // 第三步:主持人随机打开NUM_ALL_OPENED_DOORS扇空门
                int[] openedDoors = new int[NUM_ALL_OPENED_DOORS];
                
                for(int p = 0; p < NUM_ALL_OPENED_DOORS ; p++){
                    do {
                        openedDoors[p] = random.nextInt(NUM_ALL_DOORS);
                    } while (allDoors[openedDoors[p]]!= 0 );  
                             /** 排除掉有奖的门,还有嘉宾已经选好的门和主持人已经打开过的门  >> 这个条件也可以改为: 
                                allDoors[openedDoors[p]] == 1 || allDoors[openedDoors[p]] == 2 || allDoors[openedDoors[p]] == 3 || allDoors[openedDoors[p]] == 4 */
                    allDoors[openedDoors[p]] = 4 ;  // 把主持人随机打开的那NUM_ALL_OPENED_DOORS扇空门的编号所对应的allDoors整数数组的默认值从 0 变为 4  
                }
                
                // 第四步:嘉宾的选择 >> 要不要换门的决策
                
                /**第一种情况:嘉宾选择不换门的策略,即 >> 嘉宾无须丢弃已选中的NUM_ALL_CHOSEN_DOORS扇门中的 NUM_ALL_DISCARDED_DOORS扇门,
                  * 也无须重新选择NUM_ALL_REPICKED_DOORS扇门,而只要嘉宾选中NUM_ALL_GET_WINNING_DOORS扇有奖的门,就能够获得大奖
                  * 计算嘉宾选择不换门的策略,能否会中大奖?统计能够中大奖的次数  */
                
                // 设置内部局部计数变量  count
                int count = 0 ;
                for(int q = 0 ;q < NUM_ALL_DOORS ; q++ ){
                    if (allDoors[q] == 3 ) {
                        count ++;
                    }
                }
                if( count >= NUM_ALL_GET_WINNING_DOORS){
                    stayDoorsWins++;
                }
                count = 0 ; // count 计数清零,为后续的程序运行的计数做准备
                
                
                /**第二种情况:嘉宾选择换门的策略。那么此时,嘉宾需要先丢弃已选中的NUM_ALL_CHOSEN_DOORS扇门中任意的 NUM_ALL_DISCARDED_DOORS扇门,
                        然后,再重新选择NUM_ALL_REPICKED_DOORS扇任意的>>没有被嘉宾选过、丢弃过,还有没有被主持人打开过的门。
                       接下来,嘉宾也是只要选中NUM_ALL_GET_WINNING_DOORS扇有奖的门,就能够获得大奖  */
                
                // 1、先随机丢弃掉已选中的NUM_ALL_CHOSEN_DOORS扇门中的 NUM_ALL_DISCARDED_DOORS扇门
                for(int d = 0 ; d < NUM_ALL_DISCARDED_DOORS ; d++ ){
                    
                    int[] discardedDoors = new int[NUM_ALL_DISCARDED_DOORS];
                    do {
                        discardedDoors[d] = random.nextInt(NUM_ALL_DOORS);
                    } while ( !(allDoors[discardedDoors[d]] == 2 || allDoors[discardedDoors[d]] == 3) ); // 嘉宾随机选择要丢弃掉的他(她)自己已经选择过的NUM_ALL_DISCARDED_DOORS扇门的筛选条件

                    if(allDoors[discardedDoors[d]] == 2 ){
                        allDoors[discardedDoors[d]] = 5 ;  // 把嘉宾随机丢弃掉的那NUM_ALL_DISCARDED_DOORS扇空门的编号所对应的allDoors整数数组的值从  2  变为 5 
                    }else if (allDoors[discardedDoors[d]] == 3) {
                        allDoors[discardedDoors[d]] = 6 ;  // 把嘉宾随机丢弃掉的那NUM_ALL_DISCARDED_DOORS扇有奖的门的编号所对应的allDoors整数数组的值从 3  变为 6
                    }
                }
                
                // 2、再重新选择NUM_ALL_REPICKED_DOORS扇任意的,而且是,没有被嘉宾选过、丢弃过,还有没有被主持人打开过的门 >> 也就是在allDoors数组数值为 0 或者 1 的门里面来随机选择。
                for(int r = 0 ; r < NUM_ALL_REPICKED_DOORS; r++ ){
                    
                    int[] repickedDoors = new int[NUM_ALL_REPICKED_DOORS];
                    do {
                        repickedDoors[r] = random.nextInt(NUM_ALL_DOORS);
                    } while ( allDoors[repickedDoors[r]] != 0 &&  allDoors[repickedDoors[r]] != 1 );  
                      /** 这个条件可以改为: allDoors[repickedDoors[r]] == 2 
                      || allDoors[repickedDoors[r]] == 3 || allDoors[repickedDoors[r]] == 4 || allDoors[repickedDoors[r]] == 5 
                      || allDoors[repickedDoors[r]] == 6 || allDoors[repickedDoors[r]] == 7 || allDoors[repickedDoors[r]] == 8  */
                    
                    if(allDoors[repickedDoors[r]] == 0 ){
                        allDoors[repickedDoors[r]] = 7 ;  // 把嘉宾随机重选选中的这扇空门的编号所对应的allDoors整数数组的默认值从 0变为 7 
                    }else if (allDoors[repickedDoors[r]] == 1) {
                        allDoors[repickedDoors[r]] = 8 ;  // 把嘉宾随机重选选中的这扇有奖的门的编号所对应的allDoors整数数组的值从 1变为 8 
                    }
                }
                
                // 3、计算嘉宾选择换门的策略后,中大奖的次数
                for(int t = 0 ; t < NUM_ALL_DOORS ; t++ ){
                    if (allDoors[t] == 3 || allDoors[t] == 8) {
                        count ++;
                    }
                }
                if( count >= NUM_ALL_GET_WINNING_DOORS){
                    switchDoorsWins ++;
                }
             }
            
            // 输出程序的第(i+1)次结果
            System.out.println("第  "+ (i+1) +" 次测试的结果如下: \n");
            System.out.println("不换门策略获胜次数: " + stayDoorsWins + "次 。");
            System.out.println("换门策略获胜次数: " + switchDoorsWins + "次 。");
            System.out.println("不换门策略获胜的概率为: " + stayDoorsWins/(double)NUM_ITERATIONS);
            System.out.println("换门策略获胜的概率为: " + switchDoorsWins/(double)NUM_ITERATIONS);
            System.out.println("************************************************* ");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("\n >> 整个程序运行用时:  " + (endTime - startTime)/1000D + " 秒!");
    }
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值