青训营 X 豆包MarsCode AI 刷题

167 阅读6分钟

策略大师:小I和小W的数字猜谜挑战

题目描述

在一个数字游戏中,数字 1 到 n 中有一个是幸运数字,且这个数字是等概率随机选择的。玩家 小I 和 小W 轮流从这些数字中猜测幸运数字,小I 总是先开始猜。

游戏规则如下:每轮游戏后,主持人会宣布猜测结果是太大了、太小了,还是正确的。如果猜中,那么该轮猜测者即为游戏的获胜者。

假设 小I 和 小W 都采取最优策略,并且都知道对方也是如此,本题要求计算 小I 获胜的概率。请输出保留五位小数的结果。

测试样例

样例1:

输入:n = 2 输出:'0.50000'

样例2:

输入:n = 3 输出:'0.66667'

样例3:

输入:n = 4 输出:'0.50000'

样例4:

输入:n = 5 输出:'0.60000'

样例5:

输入:n = 10 输出:'0.50000'

整体目标

这段代码主要是要根据给定的整数 n,通过特定的计算逻辑求出一个与概率相关的值,并将其格式化为保留五位小数的字符串形式返回。

具体思路步骤

  1. 基础情况判断

    • 首先,代码会检查输入的 n 是否等于 1。如果 n 等于 1,就直接返回固定值 "1.00000"。这是因为对于 n = 1 的特殊情况,其对应的结果是明确已知的。
  2. 动态规划数组初始化

    • 当 n 不等于 1 时,创建一个长度为 n + 1 的数组 dp(在 Python 中是列表),并将 dp[1] 初始化为 1.0。这个数组 dp 将用于存储中间计算结果,每个元素 dp[i] 会表示与整数 i 相关的某种概率值(最终结果是 dp[n])。
  3. 迭代计算 dp 数组的值(核心逻辑)

    • 接下来,通过一个外层循环从 i = 2 到 n 遍历。对于每个 i

      • 首先初始化一个变量 max_prob 为 0.0,这个变量用于在后续的内层循环中记录当前 i 对应的最大概率值。

      • 然后进入内层循环,从 k = 1 到 i 遍历。对于每个 k

        • 先计算一个基础概率 prob,其值为 1.0 / i。这可以理解为某种初始的、平均的概率情况。
        • 如果 k > 1,需要考虑之前的情况对当前概率的影响。此时会加上 (k - 1) / i * (1 - dp[k - 1]) 这一项。这里的含义是,当 k > 1 时,前面 k - 1 个元素的情况会以一定概率影响到当前的概率计算,具体就是前面 k - 1 个元素中某个元素导致当前这次操作不成功的概率(1 - dp[k - 1])乘以其权重 (k - 1) / i
        • 类似地,如果 k < i,需要考虑后面的情况对当前概率的影响,所以会加上 (i - k) / i * (1 - dp[i - k])。这里是后面 i - k 个元素中某个元素导致当前这次操作不成功的概率(1 - dp[i - k])乘以其权重 (i - k) / i
        • 在每次内层循环计算完 prob 后,将其与当前记录的最大概率值 max_prob 进行比较,如果 prob 更大,就更新 max_prob
      • 当内层循环结束后,将当前 i 对应的最大概率值 max_prob 赋值给 dp[i],这样就完成了 dp[i] 的计算。

  4. 结果格式化返回

    • 最后,当所有的 dp 数组元素都计算完成后,将 dp[n] 按照保留五位小数的格式进行格式化,得到最终要返回的字符串结果。

实现

代码解释

  • 首先,函数会检查传入的 n 是否等于 1。如果 n 等于 1,那么直接返回字符串 "1.00000",这可能是针对 n = 1 这种特殊情况预先定义好的结果。

  • 当 n 不等于 1 时,创建一个名为 dp 的列表,其长度为 n + 1,并且将列表中的所有元素初始化为 0.0。然后,将 dp[1] 这个元素设置为 1.0。这里的 dp 列表将用于存储与不同整数相关的中间计算结果,每个元素 dp[i] 大致会对应到与整数 i 相关的某种概率值(最终我们要得到的是 dp[n] 的值)。 进入一个外层循环,循环变量 i 从 2 开始,一直到 n(包含 n)。对于每一个 i 值:

  • 首先创建一个变量 max_prob,并将其初始化为 0.0。这个变量的作用是在后续的内层循环中,用来记录对于当前的 i,通过不同的 k 值计算出来的概率中的最大值。

  • 然后进入一个内层循环,循环变量 k 从 1 开始,一直到 i(包含 i)。对于每一个 k 值,先计算一个基础概率 prob,它的值为 1.0 除以当前的 i 值。

    • 在内层循环中,对于每个 k 值:

    • 如果 k 大于 1,就需要考虑之前的情况对当前概率的影响。此时会在基础概率 prob 的基础上,加上 (k - 1) / i * (1 - dp[k - 1]) 这一项。这里的含义是,当 k > 1 时,前面 k - 1 个元素的情况会以一定概率影响到当前的概率计算。具体来说,前面 k - 1 个元素中某个元素导致当前这次操作不成功的概率(用 1 - dp[k - 1] 表示)乘以其权重 (k - 1) / i,然后累加到当前的概率 prob 上。

    • 类似地,如果 k 小于 i,需要考虑后面的情况对当前概率的影响,所以会在基础概率 prob 的基础上,加上 (i - k) / i * (1 - dp[i - k])。这里是后面 i - k 个元素中某个元素导致当前这次操作不成功的概率(用 1 - dp[i - k] 表示)乘以其权重 (i - k) / i,然后累加到当前的概率 prob 上。

    • 在内层循环中,每次计算完新的 prob 值后,就将它与当前记录的最大概率值 max_prob 进行比较。如果新的 prob 值更大,就将 max_prob 更新为这个新的更大的值。这样,当内层循环结束时,max_prob 就会记录下对于当前的 i,通过不同的 k 值计算出来的概率中的最大值。

    • 当内层循环结束后,将当前 i 对应的最大概率值 max_prob 赋值给 dp[i],这样就完成了 dp[i] 的计算,也就是更新了 dp 列表中与当前 i 对应的元素的值。

    • 当外层循环结束,也就是所有的 dp 列表元素都按照上述逻辑计算完成后,将 dp[n] 按照保留五位小数的格式进行格式化。这里使用了字符串的 format 方法,将 dp[n] 格式化为一个保留五位小数的字符串,然后将这个字符串作为函数的最终结果返回。