本文涉及知识点
C++动态规划
LeetCode837. 新 21 点
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 k 分时抽取数字。 抽取时,她从 [1, maxPts] 的范围中随机获得一个整数作为分数进行累计,其中 maxPts 是一个整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得 k 分 或更多分 时,她就停止抽取数字。
爱丽丝的分数不超过 n 的概率是多少?
与实际答案误差不超过 10-5 的答案将被视为正确答案。
示例 1:
输入:n = 10, k = 1, maxPts = 10
输出:1.00000
解释:爱丽丝得到一张牌,然后停止。
示例 2:
输入:n = 6, k = 1, maxPts = 10
输出:0.60000
解释:爱丽丝得到一张牌,然后停止。 在 10 种可能性中的 6 种情况下,她的得分不超过 6 分。
示例 3:
输入:n = 21, k = 17, maxPts = 10
输出:0.73278
提示:
0 <= k <= n <= 104
1 <= maxPts <= 104
动态规划
动态规划的状态表示
dp[i] 表示抽取i的可能数。空间复杂度:O(n+maxPts)
动态规划的状态方程
枚举后置状态,每种后置状态枚举最后一次抽取的数字。
dp[i] +=
F
o
r
j
:
1
m
a
x
P
t
s
d
p
[
i
−
k
]
For_{j:1}^{maxPts}dp[i-k]
Forj:1maxPtsdp[i−k] st i-k < n
用前缀和或滑动窗口,单个状态转移的时间复杂度为:O(1)
故总时间复杂度为:O(n+maxPts)
动态规划的初始值
dp[0]为0
动态规划的填表顺序
从1到n-1+maxPts
动态规划的返回值
sum(dp[1…k-1])/sum(dp[1…])
此题歧义
如:k=3 n = 3 maxPts=2 ,共有五种可能111 112 12 21 22
dp[3]=3 dp[4]=2,故概率应该是0.6
答案是:0.625
我的代码
class Solution {
public:
double new21Game(int n, int k, int maxPts) {
vector<long long> dp (k + maxPts);
dp[0] = 1;
vector<long long> preSum = { 0,1 };
for (int i = 1; i < k + maxPts; i++) {
int begin = max(i - maxPts,0);
dp[i] = preSum.back() - preSum[begin];
if (i < k) {
preSum.emplace_back(preSum.back() + dp[i]);
}
}
auto sum1 = accumulate(dp.begin()+k , dp.begin() + n+1,0.0);
auto sum2 = accumulate(dp.begin()+k, dp.end(), 0.0);
return sum1 / sum2;
}
};
官方的解法
dp[4] 无法继续 必定超n,故0
dp[3] 无法继续 几率1
dp[2] 可能是1或2,则结果是(dp[3]+dp[4])/2 = 0.5
dp[1]可能是1或2 ,则结果是0.75
dp[0]是0.625
动态规划的状态表示
dp[x]表示已经x分后,不超的记录。
动态规划的转移方程。
{ 0 ( x > = k ) 且 ( x > n ) 1 ( x > = k ) 且 ( x < n ) ( ∑ j : x + 1 m d p [ j ] ) / ( m − x ) 其中 m = m i n ( k − 1 + m a x P t s , x + m a x P t s ) o t h e r \begin{cases} 0 && (x >= k ) 且 (x > n )\\ 1 && ( x>=k )且(x < n ) \\ (\sum_{j:x+1}^{m}dp[j] )/(m-x) 其中 m = min(k-1+maxPts,x+maxPts) && other\\ \end{cases} ⎩ ⎨ ⎧01(∑j:x+1mdp[j])/(m−x)其中m=min(k−1+maxPts,x+maxPts)(x>=k)且(x>n)(x>=k)且(x<n)other
动态规划的填表顺序
i = k-1 : 0
动态规划的初始值
初始化x >= k
动态规划的返回值
dp[0]
代码
class Solution {
public:
double new21Game(int n, int k, int maxPts) {
vector<double> dp (k + maxPts);
double sum = 0;
for (int i = k; i <= min(n,(int)dp.size()-1); i++) {
dp[i] = 1;
sum++;
}
for (int i = k - 1; i >= 0; i--) {
const int m = min(k - 1 + maxPts, i + maxPts);
if (m + 1 < dp.size()) {
sum -= dp[m + 1];
}
dp[i] = sum / (m - i);
sum += dp[i];
}
return dp[0];
}
};
单元测试
template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{
Assert::AreEqual(t1, t2);
}
void AssertEx( double t1, double t2)
{
auto str = std::to_wstring(t1) + std::wstring(1,32) + std::to_wstring(t2);
Assert::IsTrue(abs(t1 - t2) < 1e-5,str.c_str() );
}
template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
Assert::AreEqual(v1.size(), v2.size());
for (int i = 0; i < v1.size(); i++)
{
Assert::AreEqual(v1[i], v2[i]);
}
}
template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
sort(vv1.begin(), vv1.end());
sort(vv2.begin(), vv2.end());
Assert::AreEqual(vv1.size(), vv2.size());
for (int i = 0; i < vv1.size(); i++)
{
AssertEx(vv1[i], vv2[i]);
}
}
namespace UnitTest
{
int n, k, maxPts;
TEST_CLASS(UnitTest)
{
public:
TEST_METHOD(TestMethod00)
{
n = 10, k = 1, maxPts = 10;
auto res = Solution().new21Game(n, k, maxPts);
AssertEx(1.0, res);
}
TEST_METHOD(TestMethod01)
{
n = 6, k = 1, maxPts = 10;
auto res = Solution().new21Game(n, k, maxPts);
AssertEx(0.6, res);
}
TEST_METHOD(TestMethod02)
{
n = 3, k = 3, maxPts = 2;
auto res = Solution().new21Game(n, k, maxPts);
AssertEx(0.62500, res);
}
TEST_METHOD(TestMethod03)
{
n = 1, k = 0, maxPts = 1;
auto res = Solution().new21Game(n, k, maxPts);
AssertEx(1.0, res);
}
TEST_METHOD(TestMethod04)
{
n = 21, k = 17, maxPts = 10;
auto res = Solution().new21Game(n, k, maxPts);
AssertEx(0.73278, res);
}
};
}
扩展阅读
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
相关推荐
我想对大家说的话 |
---|
《喜缺全书算法册》以原理、正确性证明、总结为主。 |
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。