题目:把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); } }