zoukankan      html  css  js  c++  java
  • 剑指 Offer 60. n个骰子的点数(动态规划)

    • 题目
    把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
    
    你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
    
    示例 1:
    
    输入: 1
    输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]
    示例 2:
    
    输入: 2
    输出:[0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]
    • 解法:动态规划

    说实话,这个简单题还不容易想到动态规划。

     题目目的:计算出投掷完 n枚骰子后每个点数出现的次数。点数和k出现概率计算公式为:

     扔n个骰子,所有点数出现的总次数为6^n(这里需要将所有骰子考虑成是有区别的,假如说3 2 和 2 3 不一样)。

    首先我们分写一些基本的性质,每多增加一颗骰子,骰子的和则会增加6,则n个骰子的总和在区间(n*1, n *6 )。那么最大的骰子

    这些骰子的和是由每次随机扔的骰子的点数决定,如果从一个个骰子逐渐递增去分析这个概率,其实并不好分析。那么我们从最后的第n个骰子的和j从后往前分析看看:

    首先,我们可以建立一个矩阵dp,它的行数k代表扔第n次,它的列数代表扔n次的点数和,dp[k][j]代表扔第k次,和为j的出现次数。可以很清楚的推理出,扔第n个骰子的时候,它的点数可能为1,2,3,4,5,6假设此时的点数和为j,对于扔第n-1个骰子,它的点数和则为j-1,j-2,...,j-6,这样可以递推回去。则就得到了这个公式:

    这就是动态规划的转移方程。

    那么在扔第1个骰子的时候,我们其实就可以初始化这个dp矩阵了,

    for i in range(1, 7):
         dp[1][i] = 1

    然后扔骰子的个数从2开始,骰子的和的范围是(k, 6 *k),每次扔的点数的范围是(1,6)。这里需要注意下递推回去的条件:当骰子的和j大于当前次数扔的点数i时,不然这就相当于没扔嘛。

    class Solution:
        def twoSum(self, n: int) -> List[float]:
            dp = [[0 for i in range(6*n+1)] for _ in range(n+1)]
            for i in range(1, 7):
                dp[1][i] = 1
            
            for k in range(2, n + 1):
                for j in range(k, 6 * k +1): #这里取k表示最小的骰子和为骰子个数*1
                    for i in range(1, 7):
                        if i < j: #说明第n次一定扔了骰子 
                            dp[k][j] += dp[k-1][j-i]
            total_value = pow(6, n)
    
            return list(map(lambda x: x/total_value, dp[n][n:]))
  • 相关阅读:
    Laravel artisan 命令工具
    WIN10安装office2003/7失败 WIN10安装office2003权限不足解决
    64windows位安装tensorflow
    Swing图层的应用——实现tooltip显示
    spring加载xml的六种方式
    ubuntu 添加右键打开方式,无法添加程序打开方式
    3.3.4 配置Tomcat的<Context>元素 (转)
    百度tn劫持解决办法
    java代理模式
    js作用域
  • 原文地址:https://www.cnblogs.com/yeshengCqupt/p/13572004.html
Copyright © 2011-2022 走看看