问题描述

1223. 掷骰子模拟 (Hard)

有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。

不过我们在使用它时有个约束,就是使得投掷骰子时, 连续 掷出数字 i 的次数不能超过

rollMax[i]i 从 1 开始编号)。

现在,给你一个整数数组 rollMax 和一个整数 n,请你来计算掷 n 次骰子可得到的不同点数序列的数量。

假如两个序列中至少存在一个元素不同,就认为这两个序列是不同的。由于答案可能很大,所以请返回 10^9 + 7 之后的结果。

示例 1:

输入:n = 2, rollMax = [1,1,2,2,2,3]
输出:34
解释:我们掷 2 次骰子,如果没有约束的话,共有 6 * 6 = 36 种可能的组合。但是根据 rollMax
数组,数字 1 和 2 最多连续出现一次,所以不会出现序列 (1,1) 和 (2,2)。因此,最终答案是 36-2 =
34。

示例 2:

输入:n = 2, rollMax = [1,1,1,1,1,1]
输出:30

示例 3:

输入:n = 3, rollMax = [1,1,1,2,2,3]
输出:181

提示:

  • 1 <= n <= 5000
  • rollMax.length == 6
  • 1 <= rollMax[i] <= 15

解题思路

动态规划

这一题是很明显的动态规划思路,状态定义很好想,状态转移方程也不难确定:

dp[i][j]为掷i次骰子,最后一次结果为j + 1的可能的组合,要求的答案即dp[n][0] + ... + dp[n][5],显然,我们只需排除最后rollMax[j] + 1次都是j的情况;

状态转移方程为:

if i <= rollMax[j]: \(dp[i][j] = \sum\limits_{k = 0}^{5} dp[i - 1][k]\)

else if i == rollMax[j] + 1: \(dp[i][j] = \sum\limits_{k = 0}^{5} dp[i - 1][k] - 1\)

else: \(dp[i][j] = \sum\limits_{k = 0}^{5}dp[i - 1][k] - \sum\limits_{k = 0, k\neq j}^{5}dp[i - rollMax[j] - 1][j]\)

记忆化搜索

这里我们从第n次向第一次倒着考虑,那么我们要关注的几个变量:

  • 当前投掷骰子的次数idx
  • 当前投掷的骰子数字减一,记为last_num
  • 当前数字往后的最大连续数量,记为max_len,例如\(623166\),考虑idx = 5,那么最大连续数量就是\(2\),这里的max_len要分等于rollMax[last_num]和小于rollMax[last_num]的情况来讨论,小于则可以继续选last_num,内层递归的max_lenmax_len + 1;否则必须选其他的数,同时内层递归的max_len置1;

当前递归的结果应该取下一层递归的结果之和;

边界条件,当idx == 0时,应该return 1;

cache数组的三个维度即idxlast_nummax_len,其中max_len <= 15,所以cache数组为vector<vector<vector<long>>> cache(n + 1, vector<vector<long>>(16, vector<long>(6, -1)));

代码

动态规划

class Solution {
public:
int dieSimulator(int n, vector<int> &rollMax) {
int mod = 1000000007;
if (n == 1) return 6;
vector<vector<int>> dp(n + 1, vector<int>(6, 0));
for (int i = 0; i < 6; i++) {
dp[0][i] = 1;
dp[1][i] = 1;
}
for (int i = 2; i <= n; i++) {
for (int j = 0; j < 6; j++) {
if (i <= rollMax[j]) {
dp[i][j] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3] + dp[i - 1][4] + dp[i - 1][5]) % mod;
} else if (i == rollMax[j] + 1) {
int tmp_sum = 0;
for (int k = 0; k < 6; k++) {
tmp_sum = (tmp_sum + dp[i - 1][k]) % mod;
}
dp[i][j] = (tmp_sum - 1) % mod;
} else {
int tmp_sum = 0;
int tmp_minus = 0;
for (int k = 0; k < 6; k++) {
tmp_sum = (tmp_sum + dp[i - 1][k]) % mod;
if (k == j) {
continue;
}
tmp_minus = (tmp_minus + dp[i - rollMax[j] - 1][k]) % mod;
}
dp[i][j] = (tmp_sum - tmp_minus + mod) % mod;
}
}
}
int res = 0;
for (int j = 0; j < 6; j++) {
res = (res + dp[n][j]) % mod;
}
return res;
}
};

记忆化搜索

class Solution {
public:
long dfs(int idx, vector<int> &rollMax, int max_len, int last_num, vector<vector<vector<long>>> &cache, int mod) {
if (idx == 0) {
return 1;
}
if (cache[idx][max_len][last_num] >= 0) {
return cache[idx][max_len][last_num] % mod;
}
long res = 0;
if (max_len < rollMax[last_num]) {
for (int i = 0; i < 6; ++i) {
if (i == last_num) {
res += dfs(idx - 1, rollMax, max_len + 1, i, cache, mod);
res %= mod;
} else {
res += dfs(idx - 1, rollMax, 1, i, cache, mod);
res %= mod;
}
}
} else {
for (int i = 0; i < 6; ++i) {
if (i != last_num) {
res += dfs(idx - 1, rollMax, 1, i, cache, mod);
res %= mod;
}
}
}
cache[idx][max_len][last_num] = res % mod;
return cache[idx][max_len][last_num];
}
int dieSimulator(int n, vector<int> &rollMax) {
// 尝试记忆化搜索
vector<vector<vector<long>>> cache(n + 1, vector<vector<long>>(16, vector<long>(6, -1)));
int mod = 1000000007;
return dfs(n, rollMax, 0, 6, cache, mod);
}
};

1223. 掷骰子模拟 (Hard)的更多相关文章

  1. LeetCode 1223. 掷骰子模拟 Dice Roll Simulation - Java - DP

    题目链接:1223. 掷骰子模拟 有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数. 不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[ ...

  2. python应用-掷骰子模拟-pygal

    pygal安装: Linux下: pip install pygal Windows下: python -m pip install pygal 效果如图: # -*- coding: utf-8 - ...

  3. Python绘制直方图 Pygal模拟掷骰子

    #coding=utf-8 from random import randint class Die(): """骰子类""" def __ ...

  4. 使用python实现模拟掷骰子数据分析

    Data:2020/4/8 主题:模拟实现掷骰子数据分析 编译环境:pycharm 库:pygal 说明: code 1:创建一个掷骰子类对象,类方法获得掷骰子随机数1-6,默认6个面,模拟20次将结 ...

  5. Python Tkinter小实例——模拟掷骰子

    什么是Tkinter? Tkinter 是 Python 的标准 GUI 库.Python 使用 Tkinter 可以快速的创建 GUI 应用程序. 由于 Tkinter 是内置到 python 的安 ...

  6. Python 使用matplotlib模块模拟掷骰子

    掷骰子 骰子类 # die.py 骰子类模块 from random import randint class Die(): """骰子类""&quo ...

  7. 【NOIP2012模拟10.31】掷骰子

    题目 太郎和一只免子正在玩一个掷骰子游戏.有一个有N个格子的长条棋盘,太郎和兔子轮流掷一个有M面的骰子,骰子M面分别是1到M的数字.且掷到任意一面的概率是相同的.掷到几.就往前走几步.当谁走到第N格时 ...

  8. TurnipBit开发板掷骰子小游戏DIY教程实例

    转载请以链接形式注明文章来源(MicroPythonQQ技术交流群:157816561,公众号:MicroPython玩家汇) 0x00前言 下面带大家用TurnipBit开发板实现一个简单的小游戏- ...

  9. python-模拟掷骰子,两个筛子数据可视化

    """ 作者:zxj 功能:模拟掷骰子,两个筛子数据可视化 版本:3.0 日期:19/3/24 """ import random impo ...

  10. Pygal之掷骰子

    python之使用pygal模拟掷骰子创建直方图: 1,文件die.py,源码如下: 1 from random import randint 2 3 class Die(): 4 '''表示一个骰子 ...

随机推荐

  1. uniapp 微信小程序 实现左侧菜单右侧列表,双向联动的效果

    <template> <view class="u-wrap"> <view class="u-search-box"> & ...

  2. JavaScript:变量的作用域,window对象,关键字var/let与function

    为什么要将这些内容放在一起,因为他们都跟初始化有关系,我们慢慢说吧. 我们在代码中,都会声明变量.函数和对象,然后由浏览器解释器(下面简称浏览器)执行: 我们还说过,变量和对象的内存结构: 那么,是什 ...

  3. 2022年7月13日,第四组 周鹏 JAVA认识的第一天,附加一个用JS写的计算器代码

    心情:╭(╯^╰)╮ ╮(╯﹏╰)╭ (╯﹏╰)b 罒ω罒 |*´Å`)ノ ( Ĭ ^ Ĭ ) (ㄒoㄒ) o(╥﹏╥)o /(ㄒoㄒ)/~~ (〒︿〒) ┭┮﹏┭┮ ε(┬┬﹏┬┬)3 ε(┬┬﹏┬ ...

  4. Transition 初步使用

    Transition Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡: 条件渲染 (使用 v-if) 条件展示 (使用 v-show) 动态组件 ...

  5. APICloud AVM框架列表组件list-view的使用、flex布局教程

    avm.js 是APICloud 推出的多端开发框架.使用 avm.js 一个技术栈可同时开发 Android & iOS 原生 App.小程序和 iOS 轻 App,且多端渲染效果统一:全新 ...

  6. pulsar集群搭建——生产环境

    pulsar集群搭建 前置条件,需要JDK环境 192.168.1.1 192.168.1.2 192.168.1.3 写入hosts 所有机器都需要执行 $ cat >>/etc/hos ...

  7. [深度学习] Python人脸识别库face_recognition使用教程

    Python人脸识别库face_recognition使用教程 face_recognition号称是世界上最简单的开源人脸识别库,可以通过Python或命令行识别和操作人脸.face_recogni ...

  8. Unity跑在Awake之前的方法

    Unity跑在Awake之前的方法 一.前言 相信大家和小黑一样,在写项目的时候遇到过以下这中情况: ____两个脚本的Awake中,都有获取信息的函数被调用.可是A脚本在B脚本获取到信息之后,才可以 ...

  9. 【CodeSmith】The System.Data.SQLite library is not installed on this computer,不能使用SQLite解决办法

    1.出现问题原因 1)System.Data.SQLite 尚未安装在您的计算机上 2)System.Data.SQLite 尚未正确配置 2.下载并安装System.Data.Sqlite [注意] ...

  10. Kinsoku jikou desu新浪股票接口变动

    1.问题原因 新浪股票接口返回如标题所示值:Kinsoku jikou desu! http://hq.sinajs.cn/list=code 新浪股票的接口变动,需要在请求头中添加Referer值. ...