LeetCode1155.掷骰子等于目标和的方法数

LeetCode1155.掷骰子等于目标和的方法数【medium】。

题目描述

这里有 n 个一样的骰子,每个骰子上都有 k 个面,分别标号为 1 到 k 。

给定三个整数 n , k 和 target ,返回可能的方式(从总共 kn 种方式中)滚动骰子的数量,使正面朝上的数字之和等于 target 。

答案可能很大,你需要对 109 + 7 取模 。

输入输出示例

示例 1:
输入:n = 1, k = 6, target = 3
输出:1
解释:你扔一个有 6 个面的骰子。
得到 3 的和只有一种方法。

示例 2:
输入:n = 2, k = 6, target = 7
输出:6
解释:你扔两个骰子,每个骰子有 6 个面。
得到 7 的和有 6 种方法:1+6 2+5 3+4 4+3 5+2 6+1。

示例 3:
输入:n = 30, k = 30, target = 500
输出:222616187
解释:返回的结果必须是对 109 + 7 取模。

提示:

  • 1 <= n, k <= 30
  • 1 <= target <= 1000

题目分析

①扔n个骰子,或者说等效于一个骰子扔n次,求得到某个固定骰子和的方案次数,为了让结果是一个固定的和,每一个骰子的点数,都对后续骰子的点数有影响。之前的状态影响当前的状态,之后的状态取决于当前的状态,且是求满足次数,也能把状态划分为多个小步骤(扔一次骰子,扔两次骰子……),第一时间应该考虑尝试动态规划解法;
进行状态定义:明确变量,扔了i个骰子,和为j,我们用f(i, j)表示扔了i个骰子时和为j的方案次数,那么我们的目的就是求f(n, target)
分析状态转移方程:扔了i个骰子和为j,对于第i个骰子,可能的取值范围是1~k,那么f(i, j) = f(i - 1, j - 1) + f(i - 1, j - 2) …… + f(i - 1, j - k), 即∑f(i − 1, j − x), x∈[1, k]
确立边界条件f(0, 0) = 1,且f(i, j) = 0当j < i(骰子点数至少是1)

题解

C#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public int NumRollsToTarget(int n, int k, int target) 
{
//f(i, j)表示使用了i个骰子时和为j的方案数目
int mod = 1000000007;
int[][] dp = new int[n + 1][];
for(int i = 0; i < n + 1; i++) {
dp[i] = new int[target + 1];
}
dp[0][0] = 1;
for(int i = 1; i < n + 1; i++) {
for(int j = 1; j < target + 1; j++) {
for(int x = 1; x <= k; x++) {
if(j >= x) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - x]) % mod;
}
}
}
}
return dp[n][target];
}