n个骰子的点数

1:题目描述

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

 

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2:题目分析

  一开始的时候认为这是一到概率论的题目,但是分析以下原来是到动态规划!我们都做过上楼梯的题目;小明在1楼,每次可以上2层楼梯或者1层楼梯,请问小明上到10层楼梯的方案个数,异曲同工之妙,不过这里是每次可以上1层,2层... ...或者6层而已。这样我们按照动态分析的方式来解析该问题。

  • 状态定义:我们定义二维数组dp,dp的行数代表侄子数,列数代表当前侄子组成之和,当前位置的值为该侄子组成该和的方案个数。
  • 转移方程:那么,当前状态dp[n][m]=dp[n-1][m-1]+dp[n-1][m-2]+dp[n-1][m-3]+dp[n-1][m-4]+dp[n-1][m-5]+dp[n-1][m-6];
  • 循环方向:我们按照从上到下,从左到右的方式来不断计算更新dp即可!!!

3:代码示例

package JianZhiOffer60;

import java.util.Arrays;

/**
 * @author :dazhu
 * @date :Created in 2020/4/19 17:44
 * @description:
 * @modified By:
 * @version: $
 */
public class Main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        System.out.println(Arrays.toString(solution.twoSum(2)));
    }
}
class Solution {
    /**
     *
     * @param n 输入侄子个数
     * @return 返回概率
     * 状态定义:dp的行数代表当前侄子个数,列数代表当前侄子的和值,该位置存放的数代表种类数
     * 状态转移:dp[n][m]代表n个侄子和为m的种类数,则有dp[n][m] = dp[n-1][m-1] +dp[n-1][m-2]+dp[n-1][m-3] +dp[n-1][m-4]+dp[n-1][m-5] +dp[n-1][m-6]
     * 如果超过了dp数组范围,则为0。
     * 控制方向:循环dp数组从上到下,从左到右。
     */
    int[][] dp ;
    public double[] twoSum(int n) {
        //初始化dp数组
        dp = new int[n+1][];
        dp[1] = new int[]{0,1,1,1,1,1,1};
        double totalKinds = Math.pow(6,n);
        //按照循环方向在状态转移方程下进行计算。
        for(int i=2;i<n+1;i++){
            //由于每一行的长度要根据当前侄子可能出现的种类数,来判断
            dp[i] = new int[6*i+1];
            for(int j=i;j<6*i+1;j++){
                dp[i][j] = fn(i-1,j-1)+fn(i-1,j-2)+fn(i-1,j-3)+fn(i-1,j-4)+fn(i-1,j-5)+fn(i-1,j-6);
            }
        }
        //创建结果概率数组
        double[] result = new double[5*n+1];
        //在dp二维数组中计算结果数组
        for(int i=0;i<5*n+1;i++){
            result[i] = dp[n][i+n]/totalKinds;
        }
        return result;
    }

    /**
     *
     * @param n 当前侄子数
     * @param m 当前侄子之和
     * @return 当前对应的种类数
     */
    public  int fn(int n,int m){
        //如果m小于0或者超过当前行的范围,则直接返回0
        if(m<0||m>=6*n+1){
            return 0;
        }
        //否则返回当前位置的值即可,即当前种类数
        else{
            return dp[n][m];
        }
    }
}

 

posted @ 2020-04-23 09:12  大朱123  阅读(196)  评论(0编辑  收藏  举报