题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
分析:动态规划,表格法,因为当前表格只与上一个表格有关,所有只需要创建两个数组即可,一个数组存储已经计算好的骰子的和出现的次数,另一个数组存储需要计算的骰子的和出现的次数,这两个数组相互依赖,彼此交换。计算的时候,需要计算次数的数组中和为s的次数等于已经计算好的数组中和为s-1,s-2,s-3,s-4,s-5,s-6中次数之和,有点类似与斐波那契额非递归算法,计算好之后再彼此交换。表述不太清楚,还是直接看代码吧。
#include <stdio.h>
#include <math.h>
#define Maxvalue 6 //筛子的点数
void print_shaizi(int n)
{
if(n<=0)
return;
int flag = 0;//用于标识记录筛子出现次数数组的序号
int *a[2];//创建两个数组,一个数组用于记录已经计算好的筛子的和出现的次数,另一个记录现在需要计算的筛子的和出现的次数,来回交换
a[0] = new int[n*Maxvalue+1];//实际只用到n*Maxvalue,多出的1是为了使数组下标和筛子的和对上,比如a[0][1]就代表筛子和为1出现的次数
a[1] = new int[n*Maxvalue+1];
int i,j,k;
for(i=0;i<n*Maxvalue+1;i++)//首先将两个数组都清0
{
a[0][i] = 0;
a[1][i] = 0;
}
for(i=1;i<=Maxvalue;i++)//首先记录第一个筛子出现的次数,只能出现1、2、3、4、5、6,将其都设为1,即出现了1次
a[flag][i] = 1;
for(k=2;k<=n;k++)//从第二个筛子开始循环,直到第n个筛子
{
for(i=0;i<k;i++)//因为i个筛子的和至少是i,所以将0到i-1的值都清0
a[1-flag][i] = 0;
for(i=k;i<=k*Maxvalue;i++)//i个筛子的和从i到i*Maxvalue,分别求各自对应出现的次数
{
a[1-flag][i] = 0;//首先将次数清0
for(j=1;j<=i&&j<=Maxvalue;j++)//当前数组和为i出现的次数等于已经计算好的数组中i-1,i-2,i-3,i-4,i-5,i-6中出现的次数之和
a[1-flag][i] += a[flag][i-j];
}
flag = 1 - flag;//数组交替,当前数组变成已经计算好的数组,已经计算好的数组变成需要计算的数组
}
double total = pow((double)Maxvalue,(double)n);//n个筛子出现的可能性是Maxvalue的n次方,注意pow返回double,参数也是double,要强制转换
double ratio;//出现的概率
for(i=0;i<=n*Maxvalue;i++)
{
if(a[flag][i]!=0)//出现的次数不为0,打印
{
ratio = (double)a[flag][i]/total;
printf("%d : %f\n",i,ratio);
}
}
delete [] a[0];
delete [] a[1];
}
int main()
{
int n;
printf("请输入筛子的个数:\n");
scanf("%d",&n);
printf("筛子的点数之和出现的概率为:\n");
print_shaizi(n);
return 0;
}