n个骰子的点数
题目
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
思路
对于n个骰子,要计算出每种点数和的概率,我们知道投掷n个骰子的总情况一共有6^n种,因此只需要计算出某点数和的情况一共有几种,即可求出该点数之和的概率。
方法一:基于递归的方法,效率较低
易知,点数之和s的最小值为n,最大值为6n,因此我们考虑用一个大小为(6n-n+1)的数组存放不同点数之和的情况个数,那么,如果点数之和为x,那么把它出现的情况总次数放入数组种下标为x-n的元素里。
确定如何存放不同点数之和的次数后,我们要计算出这些次数。我们把n个骰子分为1个骰子和n-1个骰子,这1
个骰子可能出现1~6个点数,由该骰子的点数与后面n-1个骰子的点数可以计算出总点数;而后面的n-1个骰子又可以分为1个和n-2个,把上次的点数,与现在这个骰子的点数相加,再和剩下的n-2个骰子的点数相加可以得到总点数……,即可以用递归实现。在获得最后一个骰子的点数后可以计算出几个骰子的总点数,令数组中该总点数的情况次数+1,即可结束遍历。
方法二:基于循环求骰子点数,时间性能好
用数组存放每种骰子点数和出现的次数。令数组中下标为n的元素存放点数和为n的次数。我们设置循环,每个循环多投掷一个骰子,假设某一轮循环中,我们已知了各种点数和出现的次数;在下一轮循环时,我们新投掷了一个骰子,那么此时点数和为n的情况出现的次数就等于上一轮点数和为n-1,n-2,n-3,n-4,n-5,n-6的情况出现次数的总和。从第一个骰子开始,循环n次,就可以求得第n个骰子时各种点数和出现的次数。
我们这里用两个数组来分别存放本轮循环与下一轮循环的各种点数和出现的次数,不断交替使用。
测试用例
功能测试(1,2,3,4个骰子)
特殊测试(0个)
性能测试(11个)
java代码
1 | import java.text.NumberFormat; |
总结
- int类型相除,要得到double类型,需要提前将其中一个变成double类型
例如:double ratio = (double)probabilities[i]/totalP;
- 输出百分数的方法,利用NumberFormat
1 | NumberFormat format = NumberFormat.getPercentInstance(); |
第二种方法,不是骰子点数的角度出发,而是从点数之和出发,点数之和有:f(n)=f(n-1)+……f(n-6),非常巧妙。
用两个数组交替存放,学会使用变量flag,flag=1-flag。
代码中没有把骰子的最大点数硬编码为6,而是用变量maxValue来表示,具有可拓展性。以后自己编程时也要注意这些量是否可以不用硬编码,从而提高扩展性。
提高数学建模能力,不管采取哪种思路,都要先想到用数组来存放n个骰子的每个点数和出现的次数。