题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
方法一:
要想求出n个骰子的点数之和,可以先把n个骰子分为两堆:第一堆只有一个,另一堆有n-1个。单独的那一个有可能出现从1到6的点数,需要计算从1到6的每一种点数和剩下的n-1个骰子来计算点数。接下来把剩下的n-1个骰子分成两堆,第一堆只有一个,第二堆有n-2个。重复前面的操作,直到最后只剩下一个骰子。
public class Solution{ //一个骰子最大点数 public static final int g_maxValue=6; public static void printProbability(int number){ if(number<1){ return; } //所有骰子的最大点数 int maxSum=number*g_maxValue; //数组用来保存每个可能的点数对应的次数 int[] prob=new int[maxSum-number+1]; for(int i=number;i<=maxSum;i++){ prob[i-number]=0; } //计算个数为number的骰子可能投出对应的次数 probability(number,prob); //个数为number的骰子投出的总次数 double total=Math.pow(g_maxValue,number); //计算每个点数出现的概率 for(int i=number;i<=maxSum;i++){ double ratio=(double)prob[i-number]/total; System.out.println(i+": "+ratio); } } public static void probability(int number,int[] prob){ //投出第一个骰子,i为其点数 for(int i=1;i<=g_maxValue;i++){ probability(number,number,i,prob); } } public static void probability(int original,int current,int sum,int[] prob){ //骰子为1个时,退出递归 if(current==1){ prob[sum-original]++; }else{ //第curent个的点数=第current-1个的点数+当前点数 for(int i=1;i<=g_maxValue;i++){ probability(original,current-1,i+sum,prob); } } } public static void main(String[] args){ int number=2; printProbability(number); } }
方法二:
考虑用两个数组来储存骰子点数的每一个总数出现的次数。在一次循环中,第一个数组中第n个数字表示骰子和为n出现的次数。在下一循环中,加上一个新的骰子,此时和为n的骰子出现的次数应该等于上一次循环中骰子点数和为n-1,n-2,n-3,n-4,n-5,与n-6的次数的总和,所以把另一个数组的第n个数字设为前一个数组对应的第n-1,n-2,n-3,n-4,n-5与n-6之和。
public class Solution{ //一个骰子的最大点数 public static final int g_maxValue=6; public static void printProbability(int number){ if(number<1){ return; } //所有骰子的最大点数 int maxSum=g_maxValue*number; //记录两个骰子投出点数对应的次数 int[][] prob=new int[2][maxSum+1]; for(int i=0;i<=maxSum;i++){ prob[0][i]=0; prob[1][i]=0; } int flag=0; //初始化第一个骰子投出点数对应的次数 for(int i=1;i<=g_maxValue;i++){ prob[flag][i]=1; } //从第二次开始掷骰子,假设第一个数组中的第n个数字表示骰子和为n出现的次数, //在下一循环中,我们加上一个新骰子,此时和为n的骰子出现次数应该等于上一次循环中骰子点数和为n-1,n-2,n-3,n-4,n-5, //n-6的次数总和,所以我们把另一个数组的第n个数字设为前一个数组对应的n-1,n-2,n-3,n-4,n-5,n-6之和 for(int k=2;k<=number;k++){ //k个骰子最小点数为k,则小于k点出现的次数为0 for(int i=1;i<k;i++){ prob[1-flag][i]=0; } //第k次掷骰子,和最小为k,最大为g_maxValue*k for(int i=k;i<=g_maxValue*k;i++){ //初始化,因为这个数组要重复使用,上一次的值要清0 prob[1-flag][i]=0; for(int j=1;j<=i&&j<=g_maxValue;j++){ prob[1-flag][i]+=prob[flag][i-j]; } } //切换至另外一个骰子 flag=1-flag; } double total=Math.pow(g_maxValue,number); for(int i=number;i<=maxSum;i++){ double ratio=prob[flag][i]/total; System.out.println(i+": "+ratio); } } }
posted on
浙公网安备 33010602011771号