n个骰子的点数

【题目】:

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

 一般来说骰子点数为1~6,n个筛子的点数之和可以这样理解:第n个骰子可能出现的数与前面(n-1)个骰子和的和,前面(n-1个骰子)的和为第(n-1)个骰子可能出现的数与前面(n-2)个骰子和的和。。以此类推。

【解决】

① 递归求解

第一次:将n个骰子分成两堆,第一堆只有1个骰子,第二堆有n-1个骰子
    这1个骰子有6种情况,和剩下的n-1个骰子点数相加
第二次:继续把剩下的n-1个骰子分成两堆,一堆1个,一堆n-2个...
    同样,这一个骰子还是要分成6种情况与剩下的n-2个骰子的点数相加
    同时,这一次还要把这颗骰子的点数与上一颗骰子的点数相加,之后再递归调用下一次分割。
直到:此次递归调用还剩1颗骰子时,
    我们用一个probabilities[]数组保存所有点数之和的情况,出现的次数
    在对应的probabilities【当前点数之和sum】++;

public class Solution {
    /**
     * 把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。
     * 在以下求解过程中,我们把骰子看作是有序的。
     * 例如当n=2时,我们认为(1,2)和(2,1)是两种不同的情况
     */
    public static void main(String[] args) {
        int n = 2;
        printProbabilityOfDice(n);//solution 1,递归方式
    }
    public static void printProbabilityOfDice(int n){
        if (n < 1) return;
        double total = Math.pow(6,n);//分母,每一个骰子都有6种可能的值,总共的可能右n个6的乘积的个数
        int len = n * 6 - n * 1 + 1;//n个骰子的和的范围在n * 1到n * 6之间。
        int[] times = new int[len];//记录每个和出现的次数,即分子的大小,和sum存储在下标为sum-n的位置

        for (int i = 1;i <= 6;i ++){//初始化第一个骰子,有6种可能的值
            probabilityOfDice(n,i,n,0,times);//计算每种和的出现的次数
        }
        for (int i = 0;i < len;i ++){//打印每种和出现的概率
            System.out.println("和:" + (i + n) + "出现的次数:" + times[i] + "/" + total);
        }
    }
    public static void probabilityOfDice(int n,int curDiceVal,int numOfDices,int cursum,int[] times){
        if (numOfDices == 1){//剩余骰子的个数
            int sum = cursum + curDiceVal;
            times[sum - n] ++;//得到了一个和,增加其出现的次数
        }else {
            int sum = cursum + curDiceVal;
            for (int i = 1;i <= 6;i ++){//当前骰子又有6种选择,递归进行计算
                probabilityOfDice(n,i,numOfDices - 1,sum,times);
            }
        }
    }
}

 ② 动态规划

public class Solution {
    /**
     * 有k-1个骰子时,再增加一个骰子,这个骰子的点数只可能为1、2、3、4、5或6。那k个骰子得到点数和为n的情况有:
     * (k-1,n-1):第k个骰子投了点数1
     * (k-1,n-2):第k个骰子投了点数2
     * (k-1,n-3):第k个骰子投了点数3
     * ....
     * (k-1,n-6):第k个骰子投了点数6
     * 在k-1个骰子的基础上,再增加一个骰子出现点数和为n的结果只有这6种情况!
     * 所以:f(k,n)=f(k-1,n-1)+f(k-1,n-2)+f(k-1,n-3)+f(k-1,n-4)+f(k-1,n-5)+f(k-1,n-6)
     * 初始化:有1个骰子,f(1,1)=f(1,2)=f(1,3)=f(1,4)=f(1,5)=f(1,6)=1。
     *
     * 使用dp[i][j]表示i个骰子的和为j出现的次数,dp[1][1] = dp[2][2] = ... = 1;
     * dp[i][j] = dp[i - 1][n - 1] + dp[i - 1][n - 2] + ... + dp[i - 1][n - 6];
     */
    public static void main(String[] args) {
        int n = 2;
        printProbabilityOfDice(n);//solution 2,动态规划
    }
    public static void printProbabilityOfDice(int n){
        if (n < 1) return;
        double total = Math.pow(6,n);//分母
        int maxSum = 6 * n;
        int[][] dp = new int[n + 1][6 * n + 1];
        for (int i = 1;i <= 6;i ++){//初始化
            dp[1][i] = 1;
        }
        for (int i = 2;i <= n;i ++){
            for (int j = n;j <= maxSum;j ++){
                for (int k = 1;j - k >= 1 && k <= 6;k ++){
                    dp[i][j] += dp[i - 1][j - k];//
                }
            }
        }
        for (int j = n;j <= maxSum;j ++){
            System.out.println("和为:" + j + "出现的次数为" + dp[n][j] + "/" + total);
        }
    }
}

猜你喜欢

转载自my.oschina.net/liyurong/blog/1793998
今日推荐