题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和是s,输入n,打印出s的所有可能的值出现的概率
能力解读:抽象建模,第一步是选择合理的数据结构表述问题,第二步分析模型中的内在规律,并用编程语言表达这种规律
分析:n个骰子点数和的最小值为n,最大值为6n,所有点数的排列数为6^n,因此要解决这个问题,可以先统计求出每一个点数出现的次数,然后把每一个点数出现的次数除以6^n,就能求出每个点数出现的概率
方法一:递归,求得n个骰子的点数和,把n个骰子分为两堆:第一堆只有1个,第二堆有n-1个,第一堆有可能出现1到6的点数,我们需要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数和,接下来把剩下的n-1个骰子分成两堆:第一堆只有1个,第二堆有n-2个,以此类推,递归结束的条件是最后只剩下一个骰子。但是递归实现有很多计算是重复的,从而导致当number变大时性能很慢
方法二:循环,利用两个数组存储骰子点数的每一个总数出现的次数,在一次循环中,第一个数组中的第n个数字表示骰子和为n出现的次数,在下一次循环中,加上新的骰子,则此时和为n的骰子出现的次数等于上一次循环中骰子点数和为n-1,n-2,n-3,n-4,n-5,n-6次数的总和,即f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)+f(n-6)
public class wr43printProbability {
// 递归
private static final int maxValue=6;
public static void printProbability(int number){//有n个骰子
if(number<1){
return ;
}
int maxSum=number*maxValue;//和的最大值为6n,最小值为n
int [] prob=new int[maxSum-number+1];//建立一个长为6n-n+1的数组,和为s的点数出现的次数保存到数组的第s-n个元素里
for(int i=number;i<=maxSum;i++){
prob[i-number]=0;
}
double total=Math.pow(maxValue, number);//n个骰子,每个有6个面,共有6^n个组合
probability(number,prob);//计算n到6n每种情况出现的次数
for(int i=number;i<=maxSum;i++){
double ratio=prob[i-number]/total;
System.out.println("i: "+i+" ratio: "+ratio);
}
}
public static void probability(int number,int []prob){
for(int i=1;i<=maxValue;i++){//从第一个骰子开始
probability(number,number-1,i,prob);
}
}
// 求得n个骰子的点数和,把n个骰子分为两堆:第一堆只有1个,第二堆有n-1个
// 第一堆有可能出现1到6的点数,我们需要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数和
// 接下来把剩下的n-1个骰子分成两堆:第一堆只有1个,第二堆有n-2个
// 以此类推,递归思路,递归结束的条件是最后只剩下一个骰子
public static void probability(int original,int current,int sum,int []prob){
// 参数original骰子的总个数,current为当前筛子,sum当前之和,prob是贯穿始终的数组
if(current==0){
prob[sum-original]++;
}
else{
for(int i=1;i<=maxValue;i++){
probability(original,current-1,sum+i,prob);
}
}
}
// 循环
public static void printProbabilityCicle(int number){
if(number<1){
return ;
}
int maxSum=number*maxValue;
int [][]prob=new int[2][maxSum+1];
int flag=0;
for(int i=1;i<=maxValue;i++){
prob[flag][i]=1;
}
for(int k=2;k<=number;k++){
flag=1-flag;
for(int i=1;i<k;i++){
prob[flag][i]=0;
}
for(int i=k;i<=maxValue*k;i++){
int count=1;
prob[flag][i]=0;
while(i-count>0 && count<= 6){
prob[flag][i]+=prob[1-flag][i-count];
count++;
}
}
}
double total=Math.pow(maxValue, number);
for(int i=number;i<=maxSum;i++){
double ratio=prob[flag][i]/total;
System.out.println("i: "+i+" ratio: "+ratio);
}
}
public static void main(String []args){
// printProbability(2);
printProbabilityCicle(2);
}
}