n个骰子的点数--总结

来源:互联网 发布:电话录音软件 iphone 编辑:程序博客网 时间:2024/05/17 21:49

 百度2010年某个部门(不记得是哪个了)的实习生笔试题第一题就是这种题,只是一点小小的改动而已。

 

原题依然来源于网络中某位大侠的BLOG,感谢提供素材:)

 

写这篇blog是因为原文中提到的方法和原文评论中的方法相关比较大,评论中的方法用到了DP,效率好很多。后来仔细想想,这种实现方法用“表格法”来解释更恰当,至底向上填写表格,最终得到结果。另外,这种至底向上的填表法,当前表格的值只与下一层表格的值有关,所以实现中并没有分配所有表格空间,只用了两行,一行保存上一次的结果,另一行保存现在正在计算的值,这里是可以节省很多空间的。这种方法我记得在《算法导论》的“动态规划”一章有详述。

 

 

题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。

 

先分析思路,再看实现。

 

首先解决前提性的问题:一个骰子的点数只可能是[1,6],所以S的值的取值范围是[n,6n],这里当然只考虑整数。

 

思路一:统计各个S值出现的次数,然后

 

      各个S值出现的概率 = 各个S值出现的次数 / n个骰子所有点数的排列数

 

 

其中,n个骰子所有点数的排列数等于6n,而各个S值出现的次数就需要建立一个数组来进行统计。这时,问题就变成怎样来求各个S出现的次数了。方法我直接引用原文的文字如下:

 

 

==========================  以下文字引用自原文 ============================

 

分析:玩过麻将的都知道,骰子一共6个面,每个面上都有一个点数,对应的数字是1 6之间的一个数字。所以,n个骰子的点数和的最小值为n,最大值为6n。因此,一个直观的思路就是定义一个长度为6n-n的数组,和为S的点数出现的次数保存到数组第S-n个元素里。另外,我们还知道n个骰子的所有点数的排列数6^n。一旦我们统计出每一点数出现的次数之后,因此只要把每一点数出现的次数除以6^n,就得到了对应的概率。

该思路的关键就是统计每一点数出现的次数。要求出n个骰子的点数和,我们可以先把n个骰子分为两堆:第一堆只有一个,另一个有n-1个。单独的那一个有可能出现从16的点数。我们需要计算从16的每一种点数和剩下的n-1个骰子来计算点数和。接下来把剩下的n-1个骰子还是分成两堆,第一堆只有一个,第二堆有n-2个。我们把上一轮那个单独骰子的点数和这一轮单独骰子的点数相加,再和剩下的n-2个骰子来计算点数和。分析到这里,我们不难发现,这是一种递归的思路。递归结束的条件就是最后只剩下一个骰子了。

 

==========================  以上文字引用自原文 ============================

 

思路一明晰了,代码应该不难写,同样引用原文的代码:

 

思路二:利用基本的概率论知识,而不需要统计所有可能的S出现的次数。为了方便,这里先讨论某个S出现的概率,设为P(S),则有

    P(S) = P(S1) + P(S2) + ... + P(Sk)

S1,S2...Sk表示和为S的各种骰子组合。另外,

 

    P(Si) = P(a1) + P(a2) + ... + P(an)

其中,P(ai)表示第i个骰子出现值为ai的概率。

很简单的,就是一个概率论的东西,很基本的。不需要统计所有可能的S出现的次数,而直接计算和为S的各种可能的骰子组合的概率,然后把所有组合的概率相加,就得到了和为S的概率了。

先把代码贴出来吧,没上机测试,细节上有什么问题不太清楚,关键是主程序应该是没问题的。代码来源于原文的评论中。

如果看懂了代码就不用看下面的了,下文只是代码的一个注释,以免以后老了脑子不好使看不懂……

这种方法是DP中的表格法,用至底向上填表的方式,把结果求出来。用表格法,一行代表一个骰子,列表示各个S值,所以一共有6*N列。本来是要用N行的,可是这里只用了一个二维的数组,因为现在计算的值只与前一次计算的值相关,所以其中一行保存上一次计算的结果,另一行保存正在计算的结果,这样可以节省大量的空间。

代码中的N是指有几个骰子,或者说是掷了几次骰子。第一个for循环表示第一个骰子的情况,然后第二个for循环中的k表示第k个骰子。当到了第k个骰子时,内层的for循环开始对和个S的值进行分析,i表示的就是各个不同的S。在这个循环里,考虑第k个骰子的6种不同取值(j表示的就是骰子的点数),然后在while循环里把所有可能的得到和为S的组合的概率进行相加。flag的作用很简单,就是在二维数组里对当时值和已经计算得到的值进行区别,他只出现在数组的行号处。

 

 

画个图的话,就容易理解了。有时间再上图吧。

 

最后,附上原文地址:http://zhedahht.blog.163.com/blog/static/254111742009101524946359/

原创粉丝点击