题目描述:
扔 n 个骰子,向上面的数字之和为 S。给定 Given n,请列出所有可能的 S 值及其相应的概率。
注意事项
You do not care about the accuracy of the result, we will help you to output results.
给定 n = 1
,返回 [ [1, 0.17], [2, 0.17], [3, 0.17], [4, 0.17], [5, 0.17], [6, 0.17]]
。
题目分析:
题目:You do not care about the accuracy of the result, we will help you to output results.
开始还自己处理浮点数,结果题目有说不用处理。。。
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。
1.假设在n个骰子和点数和Sum的情况下,次数m = f(n,Sum)
2.当然n-1块骰子的情况下,一般情况下可投出Sum-1、Sum-2、Sum-3、Sum-4、Sum-5、Sum-6的情况,即留给最后一块骰子1-6的投掷空间;
(k-1,n-1):第k个骰子投了点数1
(k-1,n-2):第k个骰子投了点数2
(k-1,n-3):第k个骰子投了点数3
....
(k-1,n-6):第k个骰子投了点数6
AllPro = f(n,Sum) = f(n-1,Sum-1) + f(n-1,Sum-2) + f(n-1,Sum-3) + f(n-1,Sum-4) + f(n-1,Sum-5) + f(n-1,Sum-6)
3.特殊情况一,Sum - i < 1 *(n-1),即留给n-1块骰子的投掷空间已经比n-1块骰子的最小点数和还小了!
AllPro = f(n,Sum) = f(n-1,Sum-i) + f(n-1,Sum-i-1) + ... + f(n-1,Sum-5) + f(n-1,Sum-6)
4.特殊情况二,Sum - i > 6 *(n-1),即留给n-1块骰子的投掷空间已经比n-1块骰子的最大点数和还大了!
AllPro = f(n,Sum) = f(n-1,Sum-1) + f(n-1,Sum-2) + ... + f(n-1,Sum-i) + f(n-1,Sum-i-1)
例如 n = 1时:
f(1,1) = f(1,2) = f(1,3) = f(1,4) = f(1,5) = f(1,6) = 1
而 n = 2时:
f(2,2) = f(1,1) = 1
f(2,3) = f(1,2) + f(1,1) = 2
...
f(2,6) = f(1,5) + f(1,4) + f(1,3) + f(1,2) + f(1,1)
f(2,7) = f(1,6) + f(1,5) + f(1,4) + f(1,3) + f(1,2) + f(1,1) = 6
f(2,8) = f(1,6) + f(1,5) + f(1,4) + f(1,3) + f(1,2) = 5
...
此时 f(2,2) 、f(2,3) ... f(2,6)就满足特殊情况一,而 f(2,8) 、f(2,9) ... f(2,12)就满足特殊情况二;
递归处理会超时,这里使用数组保存每n个骰子的Sum和值可能性,再生成n+1中骰子的和值可能性分布;
代码偷了个懒,和值分布是对称的,这里只生产一半数据,后面数据复制过去即可。
数组result[i],因为第 i 个元素代表 i+1个骰子,所以长度为 5*(i+1) +1,
顶峰值为第3n个元素,由于 i 为奇数时,数组长度为偶数,顶峰值有两个,3n和3n+1,同样是对称的。
贴一下和值可能性分布数组:
n=1 : [1, 1, 1, 1, 1, 1]
n=2 : [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]
n=3 : [1, 3, 6, 10, 15, 21, 25, 27, 27, 25, 21, 15, 10, 6, 3, 1]
n=4 : [1, 4, 10, 20, 35, 56, 80, 104, 125, 140, 146, 140, 125, 104, 80, 56, 35, 20, 10, 4, 1]
n=5 : [1, 5, 15, 35, 70, 126, 205, 305, 420, 540, 651, 735, 780, 780, 735, 651, 540, 420, 305, 205, 126, 70, 35, 15, 5, 1]
n=6 : [1, 6, 21, 56, 126, 252, 456, 756, 1161, 1666, 2247, 2856, 3431, 3906, 4221, 4332, 4221, 3906, 3431, 2856, 2247, 1666, 1161, 756, 456, 252, 126, 56, 21, 6, 1]
n=7 : [1, 7, 28, 84, 210, 462, 917, 1667, 2807, 4417, 6538, 9142, 12117, 15267, 18327, 20993, 22967, 24017, 24017, 22967, 20993, 18327, 15267, 12117, 9142, 6538, 4417, 2807, 1667, 917, 462, 210, 84, 28, 7, 1]
n=8 : [1, 8, 36, 120, 330, 792, 1708, 3368, 6147, 10480, 16808, 25488, 36688, 50288, 65808, 82384, 98813, 113688, 125588, 133288, 135954, 133288, 125588, 113688, 98813, 82384, 65808, 50288, 36688, 25488, 16808, 10480, 6147, 3368, 1708, 792, 330, 120, 36, 8, 1]
n=9 : [1, 9, 45, 165, 495, 1287, 2994, 6354, 12465, 22825, 39303, 63999, 98979, 145899, 205560, 277464, 359469, 447669, 536569, 619569, 689715, 740619, 767394, 767394, 740619, 689715, 619569, 536569, 447669, 359469, 277464, 205560, 145899, 98979, 63999, 39303, 22825, 12465, 6354, 2994, 1287, 495, 165, 45, 9, 1]
n=10 : [1, 10, 55, 220, 715, 2002, 4995, 11340, 23760, 46420, 85228, 147940, 243925, 383470, 576565, 831204, 1151370, 1535040, 1972630, 2446300, 2930455, 3393610, 3801535, 4121260, 4325310, 4395456, 4325310, 4121260, 3801535,3393610, 2930455, 2446300, 1972630, 1535040, 1151370, 831204, 576565, 383470, 243925, 147940, 85228, 46420, 23760, 11340, 4995, 2002, 715, 220, 55, 10, 1]
源码:
class Solution: # @param {int} n an integer # @return {tuple[]} a list of tuple(sum, probability) def dicesSum(self, n): # Write your code here if n == 0 : return None result = [ [1,1,1,1,1,1], ] # if n == 1: return result[0] # 计算n个骰子出现的各个次数和 for i in range(1,n): x = 5*(i+1)+1 result.append([0 for _ in range(x)]) for j in range(x): if j < 6: result[i][j] = (sum(result[i-1][0:j+1])) elif 6 <= j <= 3*i+2: result[i][j] = (sum(result[i-1][j-5:j+1])) else: break left = 0 right = len(result[i]) - 1 while left <= right: result[i][right] = result[i][left] left += 1 right -= 1 res = result[-1] all = float(sum(res)) other = [] # 第i个元素代表骰子总和为n+i for i,item in enumerate(res): # pro = self.round(item/all) # 自己写的四舍五入算法和LintCode有出入,其实网站自身会处理数据,这里不再做处理 pro = item/all other.append([n+i,pro]) return other def round(self,num): # 将概率值四舍五入 num = num*100 num = int(2*num)/2+int(2*num)%2 num = num/100.0 return num