zoukankan      html  css  js  c++  java
  • n个骰子的点数

    剑指offer上43题

    n个骰子,朝上一面的点数之和为S,求S的所有可能的值的概率

    有两种方法 1.递归

    2.动态规划 f(n) = f(n-1)+f(n-2)+....+f(n-6);

    贴代码:

    package testAbstractClass;
    
    public class xiecheng {
        //有n个骰子,所有朝上的点数之和为S 求S的所有可能值出现的概率。
        public static int six=6;
        public static void main(String args[]){
            //printpro(2);
            printProbability(2);
            
        }     
        //以下为递归解法
        public static void printProbability(int n){
            if(n<1) return;
            int maxsum = n*six;
            int minsum = n*1;
            //将和为s的出现次数放在s-n个位置 index=s-n;index一共是0-5n
            int [] mark_num = new int [maxsum-minsum+1];//自动初始化为0;
            probability(n, mark_num);
           
            int total = (int) Math.pow(six, n);//总共的可能数目为6^n
            for(int i=n;i<=maxsum;i++){
                double ratio = (double)mark_num[i-n]/total;
                System.out.println("和为"+i                    +"出现的概率是"+ratio);
            }
        }
        //获取所有的可能 并将出现的次数存在一个5n+1的数组中;
        public static void probability(int n,int [] mark_num){
            for(int i =1;i<=six;i++){
                probability(n,n,i,mark_num);
            }
        }
        //递归实现 将n个骰子,目前递归到序号,目前的和,以及标记数组传进来。当序号递归6次 就完成一次记录 ,将对应位置上的值加1
        public static void probability(int original,int current,int sum,int [] mark_sum){
            if(current==1) mark_sum[sum-original]++;
            else{
                for(int i=1;i<=six;i++){
                    probability(original,current-1,i+sum,mark_sum);
                }
            }
            }
      
           }

    第二种方法是动态规划,记录前一轮状态中的骰子的值 

    /**
         * 解法2 动态规划法;用两个数组存储骰子点数的每一个总数出现的次数: 数组的第n个数字达标骰子和为n出现的次数,
         * 在下一轮循环中,加上一个新的骰子,此时和为n的骰子出现的次数应该等于上一轮骰子点数为n-1,n-2,n-3,n-4,n-5,n-6的次数总和。
         * f(n) = f(n-1)+...f(n-6);
         */
        public static  void printpro(int n){
            int [][] pro =  new int [2][six*n+1];
            
            
            int flag =0;
            //第一个骰子的状态 就是dp的出示状态
            for(int i=1;i<=six;i++) pro[flag][i] =1;
            //第二个骰子到第n个骰子
            for(int j=2;j<=n;j++){
                //将前0-j置零 因为j个骰子 点数最少都是j*1
                for(int i=0;i<j;i++) pro[1-flag][i] =0;
                
                for(int i=j;i<=six*j;i++){
                    pro[1-flag][i] =0;
                    //i-1 i-2...i-6
                    for(int k=1;k<=i&&k<=six;k++){
                        pro[1-flag][i]+=pro[flag][i-k];
                    }
                }
                //遍历完一次更改一次flag
                flag =1-flag;
                
            }
            int maxsum = n*six;
            double total = (int) Math.pow((double)six, (double)n);//总共的可能数目为6^n
            for(int i=n;i<=maxsum;i++){
                double ratio = (double)pro[flag][i]/total;
                System.out.println("和为"+i+"出现的概率是"+ratio);
            }
            
        }
            
            
            

    第二种方法时间上效率较高。只比第一种方法多费了o(n)的空间。

  • 相关阅读:
    java第十三周作业
    java第十三周随堂
    安卓作业
    5.29 第十三周作业
    5.28第十三周上机练习
    5.22第十二周作业
    5.21第十二章上机练习
    5.15 第十一周作业
    5.14 第十一周 上机练习
    5.7第十周上机练习
  • 原文地址:https://www.cnblogs.com/CongLollipop/p/6636413.html
Copyright © 2011-2022 走看看