n个色子,每个色子m面,每一面的值分别是1-m。你将n个色子同时抛,落地后将所有朝上面的数字加起来,记为sum。给定一个数字x,如果sum>x,则你赢。给定n,m,x,求你赢的概率。
- 1<=n<=100
- 1<=m<=10
- m<=x< n*m
分析
这个题目的描述,是将具体的问题一般化了。掌握了,这个问题的分析,就可以对这类问题通吃。一个具体的情况是什么呢?两个色子,每个色子六面,同时抛,求朝上数字和大于某一个值的概率。这个情况比较简单,两个色子同时抛,一共36种情况,注意这里有的和是相同的。此时,最少可以通过穷举的方法,得到答案。但是本题中的意思,显然是无法通过穷举呢?那该如何分析呢?
n个色子,每个色子m面。则一共有m^n中情况(类比上面分析的36种情况)。在这些里面,有多少个和是大于x的呢?假设,f(n,x)表示n个色子,所有朝上的数字和是x的情况数量。对于某一个色子,每一面朝上的概率是1/m。假设这个色子的k面朝上,1<=k<=m,则f(n,x) = sum{f(n - 1, x - k)} 1<=k<=m。递归的终止条件是,当只有一个色子的时候,f(1,k) = 1, 1<=k<=m,其他都是0
则最终的概率为(f(n, x + 1) + … + f(n, m*n)) / m^n。每一个大于x的和的可能情况数量之和除以总的情况数量。
代码如下:
double NDiceWithMSide(int n,int m,int x)//n个色子,m个面,求和大于x的概率 { int i,j,k,MaxPoint = n*m,SumOfAll = pow(m,n); int** f = new int* [n+1]; for(i=0;i<=n;i++) { f[i] = new int[MaxPoint+1]; } for(j = 1; j<=m;j++)f[1][j] = 1;//初始化一个色子 for(i = 2;i <= n;i++) { for(j = i;j <= i*m;j++) { f[i][j] = 0; for(k=1;k<=m && k<j;k++) { f[i][j] += f[i-1][j-k];//<span style="color: rgb(51, 51, 51); font-family: Verdana, Arial, Tahoma, Helvetica, Georgia, sans-serif, STXihei, 华文黑体, Hei, 'Hiragino Kaku Gothic Pro', SimSun; line-height: 27.19999885559082px;">f(n,x) = sum{f(n - 1, x - k)} </span> } } } int sum = 0; for(i=x+1;i<= MaxPoint;i++) { sum += f[n][i]; } for(i=0;i<=n;i++)delete[] f[i]; delete[] f; return (double)sum / SumOfAll; }
如有问题,请指正,谢谢
时间: 2024-10-14 18:19:06