剑指Offer50-n个色子的点数

本文详细解析了剑指Offer中一道关于计算n个骰子点数之和的概率问题,采用动态规划方法,通过定义二维数组dp进行状态转移,最终得出所有可能点数和的概率分布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

剑指Offer典型题整理 - 争取做最好的题解
整理时间:2020年02月20日

1 题目描述

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

你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。

示例

输入: 1
输出: [0.16667,0.16667,0.16667,0.16667,0.16667,0.16667]

输入: 2
输出: [0.02778,0.05556,0.08333,0.11111,0.13889,0.16667,0.13889,0.11111,0.08333,0.05556,0.02778]

2 题解

一开始我以为这是一道数学题,想着找找规律,Emmmm,然鹅并没什么规律。后来发现这是一道动态规划题目,一直以为动态规划的题目主要用来求最XX问题的,所以没有往DP上想,看样子动态规划学的还是不太行。

2.1 定义dp与初始化

如果用二维数组实现DP,就需要定义一个行数为 n + 1 n+1 n+1,列数为 6 ∗ n + 1 6*n+1 6n+1的矩阵,dp[i][j]表示使用i个色子出现的和为j的次数。并且将下标为1的那一行初始化:

dp = [[0 for i in range(6 * n + 1)] for j in range(n + 1)]
for i in range(1, 7):
	dp[1][i] = 1
2.2 定义状态转移方程

这个问题之所以能够使用DP解决,就是因为状态可以叠加:k个色子求和的结果和k-1个色子有关。当有k-1个骰子时,再增加一个骰子,这个骰子的点数只可能为1、2、3、4、5或6。在k-1个骰子的基础上,再增加一个骰子出现点数和为n只有 下面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

所以:f(k,n)=f(k-1,n-1)+f(k-1,n-2)+f(k-1,n-3)+f(k-1,n-4)+f(k-1,n-5)+f(k-1,n-6)​

2.3 代码实现

C++代码

class Solution {
public:
    vector<double> twoSum(int n) {
        vector<vector<int>> dp(n + 1);
        for (int i = 0; i <= n; i++) {
            dp[i].resize(6 * n + 1);
        }
        for (int i = 1; i <= 6; i++) {
            dp[1][i] = 1;
        }
        for (int i = 2; i <= n; i++) {
            for (int j = i; j < 6 * i + 1; j++) {
                for (int k = 1; k <= 6; k++) {
                    if (j - k > 0) {
                        dp[i][j] += dp[i - 1][j - k];
                    }
                }
            }
        }

        vector<double> ans;
        float base = pow(6, n);
        for (int i = n; i <= 6 * n; i++) {
            ans.push_back(dp[n][i] / base);
        }
        return ans;
    }
};

python代码

class Solution(object):
    def twoSum(self, n):
        dp = [[0 for i in range(6 * n + 1)] for j in range(n + 1)]
        for i in range(1, 7):
            dp[1][i] = 1
        for i in range(2, n + 1):
            for j in range(i, 6 * i + 1):
                for k in range(1, 7):
                    if j - k > 0:
                        dp[i][j] += dp[i - 1][j - k]
        base = math.pow(6, n)
        return [counts / float(base) for counts in dp[n][n:]]

(完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值