Every day a Leetcode
题目来源:1155. 掷骰子等于目标和的方法数
解法1:动态规划
设置状态转移矩阵:
cpp
vector<vector<int>> dp(n + 1, vector<int>(target + 1, 0));
也可以设成 n*k+1 的大小,大部分情况下设置成 target+1 能节省内存。
初始化时,我们丢第一个骰子,出现 1~k 点数:
cpp
// 初始化
for (int i = 1; i <= k && i <= target; i++)
dp[1][i] = 1;
从上一层结果,丢一个骰子,状态转移到下一层。
设 i 为丢的骰子数,j 为当前层的总点数,x 为当前丢骰子的点数,枚举 x = 1~k,j-x 就是上一层丢的总点数,在满足 j - x >= i - 1 && j - x <= k * (i - 1)
的条件下,dp[i][j] += dp[i - 1][j - x],在与 MOD( 1e9 + 7) 取余。
条件j - x >= i - 1 && j - x <= k * (i - 1)
的意思是:
前 i-1 个骰子至少要丢 i-1 个点数,最多丢 k * (i - 1) 个点数。事实上,只限定 j - x >= 1 也能通过这些样例。
状态转移方程:
cpp
// 动态规划
for (int i = 2; i <= n; i++)
for (int j = 0; j <= target; j++)
{
for (int x = 1; x <= k; x++)
if (j - x >= i - 1 && j - x <= k * (i - 1))
dp[i][j] = (dp[i][j] + dp[i - 1][j - x]) % MOD;
}
代码:
c
/*
* @lc app=leetcode.cn id=1155 lang=cpp
*
* [1155] 掷骰子等于目标和的方法数
*/
// @lc code=start
class Solution
{
private:
static const int MOD = 1e9 + 7;
public:
int numRollsToTarget(int n, int k, int target)
{
vector<vector<int>> dp(n + 1, vector<int>(target + 1, 0));
// 初始化
for (int i = 1; i <= k && i <= target; i++)
dp[1][i] = 1;
// 动态规划
for (int i = 2; i <= n; i++)
for (int j = 0; j <= target; j++)
{
for (int x = 1; x <= k; x++)
if (j - x >= i - 1 && j - x <= k * (i - 1))
dp[i][j] = (dp[i][j] + dp[i - 1][j - x]) % MOD;
}
return dp[n][target];
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n * k * target)
空间复杂度:O(n * target)