n个骰子的点数

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值