LeetCode:1155. 掷骰子等于目标和的方法数(C++)

目录

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

题目描述:

实现代码与解析:

动态规划

原理思路:


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

题目描述:

        这里有 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

实现代码与解析:

动态规划

class Solution {
public:
    int mod = 1e9 + 7;
    int numRollsToTarget(int n, int k, int target) {
        
        vector f(target + 1);
        f[0] = 1; // 初始化,背包大小为0时,没有结果,为一种选择,赋值为1
        // 分组背包,每组只能选一个
        for (int i = 1; i <= n; i ++){ // 分组            
            for (int j = target; j >= 0; j--){ // 体积
                f[j] = 0; // 每个筛子都要放入背包,不能跳过,把上一次的状态清空,这是一维与一般的背包问题不同的地方
                for (int m = 1; m <= k ; m++){ // 价值
                    if (j >= m) { // 剩余体积大才能选,由于优化成了一维,所以j < m时,就直接继承了上一滚动数组的值,不用我们单独赋值了
                        f[j] = (f[j - m] + f[j]) % mod; // f[i][j] = f[i - 1][j - m] + f[i][j]; 求组合个数的递推式,当前方案,加上上一个方案
                    }
                }
            }
        }
        return f[target];
    }
};

原理思路:

        转化为分组背包问题,注释写的非常详细了,不再解析,只解释一些f[i] = 0 的代码。

        这个清零的操作确保了在每个迭代中,f[j] 包含了只考虑当前骰子面值的组合数,而不会累积之前迭代的结果。这是解决问题的关键,以确保计算的正确性,因为你不能跳过任何一个骰子的面值,而传统的分组背包是可以跳过的。

你可能感兴趣的:(LeetCode,1024程序员节,leetcode,算法)