1155. 掷骰子的N种方法
作者:互联网
1155. 掷骰子的N种方法
题目描述
这里有 d 个一样的骰子,每个骰子上都有 f 个面,分别标号为 1, 2, ..., f。
我们约定:掷骰子的得到总点数为各骰子面朝上的数字的总和。
如果需要掷出的总点数为 target,请你计算出有多少种不同的组合情况(所有的组合情况总共有 f^d 种),模 10^9 + 7 后返回。
思路分析(二维)
这个题是动态规划问题,参考一篇文章吃透背包问题!(细致引入+解题模板+例题分析+代码呈现)
的分析思路,首先,这个是一个分组背包问题,然后又是组合问题。分组背包的特点是在每个数的选择上都有好几个选择,可以把每个筛子当成普通背包的重量,不过这个重量是看可以变得。可以用三个循环,前两个循环按照题目按照0/1背包、完全背包和组合背包的要求写,第三个循环时选择重量(在本题中就是骰子的点数)。对于本题。最外面循环是骰子的个数d,然后 中间一层是target,由于这个每个骰子是不可重复用的,因此taget循环用倒序(如果是二维dp那么正序也可以),然后最后一层便是点数的循环f。本题中用dp[i] [j]表示用前i个骰子得到目标和j的组合数目,那么有dp[i] [j]+=dp[i] [k],k>=1&&k<=j
代码实现
class Solution {
public:
int numRollsToTarget(int d, int f, int target) {
const int mod=1000000007;
vector<vector<int>>dp(d+1,vector<int>(target+1,0));
//初始化
dp[0][0]=1;
//对于骰子遍历
for(int i=1;i<=d;i++)
{
//对于target的遍历
for(int j=target;j>=1;j--)
{
//对于骰子的遍历,细节1:j>=k
for(int k=1;k<=f&&j>=k;k++)
{
dp[i][j]+=dp[i-1][j-k];
dp[i][j]%=mod;
}
}
}
return dp[d][target];
}
};
思路分析(一维优化)
对于一维优化,设定dp[j]为目标和为j的组合数目。相比于二维,需要注意的一个细节便是骰子都必须用上,因此如果用假如两个骰子那么得到的最小数便是2,那么就需要dp[j],j<i需要设置为0(二维dp不用担心),另外一个细节是骰子不能摇出来0(所以不能用dp[j]直接加,需要从0开始加)。
class Solution {
public:
int numRollsToTarget(int d, int f, int target) {
const int mod=1000000007;
vector<int>dp(target+1,0);
dp[0]=1;
for(int i=1;i<=d;i++)
{
//细节1:倒序,这样加的是上一层的
for(int j=target;j>=i;j--)
{
//细节2:只加当点数为1—k的
int sum=0;
for(int k=1;k<=f&&j>=k;k++)
{
sum+=dp[j-k];
sum%=mod;
}
dp[j]=sum;
}
//细节3:小于筛子个数的设置为0
for(int j=0;j<i;j++)
dp[j]=0;
}
return dp[target];
}
};
标签:骰子,背包,target,1155,掷骰子,int,点数,方法,dp 来源: https://www.cnblogs.com/zengfanlu/p/14868883.html