【算法学习】n个骰子的点数(Java)

一、题目描述

把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。

你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

示例 1:
输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
示例 2:

输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]

二、思路分析

  1. 题目要求:求解每种情况概率,概率 = 每种情况出现次数/总次数,总次数很简单即可重复排列 6n,问题需要先计算结果有多少种,以及每种出现的次数。
  2. 每个骰子可能有六种结果,即 1-6,那么一个筛子会出现如下结果:
    在这里插入图片描述
  3. 步骤2基础上加一个筛子,会出现以下情况:在这里插入图片描述
    步骤2步骤3结果放在一块对齐如下:
    在这里插入图片描述

发现规律如下:(博主也是辗转反侧得出正确结果,并非一次猜测就正确)

  • 骰子和会落在,n - 6 * n 这个区间(区间长度 len = 6*n-n+1 = 5n + 1,加 1 的原因是含起始数字)
  • 骰子数为 N,骰子和 F(n, t) 为,n - 1 个筛子,F(n-1, t - 1) + F(n-1, t - 2) + F(n-1, t-3) + F(n-1, t-4) + F(n-1, t-5) + F(n-1, t-6),注意这里有边界条件,如 F(2, 3) = F(1, 2) + F(1, 1),F(2, 7) = F(1, 1) + F(1, 2) + F(1, 3) + F(1, 4) + F(1, 5) + F(1, 6)。

核心公式

f ( n , t ) = f ( n − 1 , t − 1 ) + f ( n − 1 , t − 2 ) + f ( n − 1 , t − 3 ) + f ( n − 1 , t − 4 ) + f ( n − 1 , t − 5 ) + f ( n − 1 , t − 6 ) f(n, t) = f(n-1, t - 1) + f(n-1, t - 2) + f(n-1, t-3) + f(n-1, t-4) + f(n-1, t-5) + f(n-1, t-6) f(n,t)=f(n1,t1)+f(n1,t2)+f(n1,t3)+f(n1,t4)+f(n1,t5)+f(n1,t6)
注意:此处有坑,注意边界条件,后面公式最多六个。

公式推导依据

上面展示 步骤2步骤3结果图,可以观察到,每增加一个筛子,给现有情况都增加了六个可能性,并且这个可能性在 +1 到 +6 范围内,因此会有上文公式。
举个例子:n = 2,sum = 4 时,sum = 4 的组合可能来自于,n = 1 时的,(1 + 3,2 + 2,3+1),因此,sum = 4 的组合情况有 1 + 1 + 1 = 3 种可能。

计算出每种情况出现的次数后,概率就很简单了。

三、参考代码

class Solution {
    public double[] dicesProbability(int n) {
        int[] a = {1, 1, 1, 1, 1, 1};//最初形式
        int num = (int)Math.pow(6, n);// 共有这些可能
        int len = 5 * n + 1;
        int[][] r = new int[n][len];//二维数组,对应 i,j 指的是 i个筛子,和为 j 的个数
        double[] r2 = new double[len];
        for(int j = 0; j < 6; j++)
            r[0][j] = a[j];

        for(int i = 1; i < n; i++){// 从 n 等于 1 开始逐个推导至 n
            int t = 5 * i + 6;// (i+1) * 6 - (i+1-1)
            for(int j = 0; j < t; j++){
                int t2 = 0;
                for(int k = (j - 5) > 0 ? j - 5 : 0; k <= j; k++)
                    t2 += r[i - 1][k];//含当前数,往前五个
                r[i][j] = t2; 
            }
        }

        for(int j = 0; j < len; j++){//根据推导结果计算比例
            r2[j] = 1.0 * r[n-1][j] / num;
        }
        return r2;
    }
}

四、测试连接

力扣

鼠小 CSDN认证博客专家 一个萌汉子
未来的路是黑的,我不知道怎么走,我需要做的就是先走着。https://smallzheng.blog.csdn.net/
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页