策略大师:小I与小W的数字猜谜挑战 | 豆包MarsCode AI刷题

140 阅读3分钟

问题描述

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

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

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

解题思路

先说结论,这个题只需要一个式子就能做出来,Pn=n2/nP_n=⌈\frac{n}{2}⌉/n(⌈ ⌉是向上取整),下面我来分析一下。

首先,给定一个 n 值, 小I 获胜的概率为 PnP_n 。 小I 从这 n 个数字中任取一个 i ,他会有 1n\frac{1}{n} 的概率立即获胜,否则,数字就被划分为了两部分,一部分是 1~(i-1) 共 i-1 个数字,另一部分是 (i+1)~n 共 n-i 个数字。幸运数字有 i1n\frac{i-1}{n} 的概率落在前一个部分,有 nin\frac{n-i}{n} 的概率落在后一个部分。

如果幸运数字落在前一个部分,就相当于从 小W 开始在 i-1 个数字中猜, 小I 获胜的概率就是 1Pi11-P_{i-1} ,另一种情况同理。并且两人都会采取最优策略,所以最终可以得到Pn=max1in(1n+i1n(1Pi1)+nin(1Pni))P_n = {max}_{1 \leq i \leq n} (\frac{1}{n} + \frac{i-1}{n} * (1 - P_{i-1}) + \frac{n-i}{n} * (1 - P_{n-i}))

接下来,我们要考虑怎么能让 PnP_n 的值最大。我首先手动计算出一些 P 的最大值 P1=11P_1=\frac{1}{1} , P2=12P_2=\frac{1}{2} , P3=23P_3=\frac{2}{3} , P4=24P_4=\frac{2}{4} , P5=35P_5=\frac{3}{5} , P6=36P_6=\frac{3}{6} , P7=47P_7=\frac{4}{7} , P8=48P_8=\frac{4}{8}(不约分可以更好地看出规律)。这里其实就已经能看出来结论了,但是还没有严谨的证明,下一步就是要证明这个结论。

数学证明

首先,可以通过很简单的数学归纳得出每一个 PnP_n 的分母就是n(不约分的情况下),为了简化计算,设 PnP_n 的分子为 ana_n ,可以得出 Pn=max1in1+((i1)ai1)+((ni)ani)n=max1inn(ai1+ani)nP_n = {max}_{1 \leq i \leq n} \frac{1 + ((i-1) - a_{i-1}) + ((n-i) - a_{n-i})}{n} = {max}_{1 \leq i \leq n}\frac{n - (a_{i-1} + a_{n-i})}{n} ,即an=max1in(n(ai1+ani))a_n = {max}_{1 \leq i \leq n}(n - (a_{i-1} + a_{n-i}))

然后我们使用数学归纳法证明 an=n2a_n = ⌈\frac{n}{2}⌉ ,已经证明在 n8n \leq 8 时命题成立。假设在 nmn \leq m 时命题成立,那么在 n=m+1n=m+1 时,为使 am+1=m+1(i12+m+1i2)a_{m+1} = m+1 - (⌈\frac{i-1}{2}⌉+⌈\frac{m+1-i}{2}⌉) 取最大值,我们进行分类讨论:若 m + 1 为奇数,令 i 为奇数则 am+1=m+22a_{m+1}=\frac{m+2}{2} ,令 i 为偶数则 am+1=m2a_{m+1}=\frac{m}{2} ;若 m + 1 为偶数,令 i 为奇数则 am+1=m+12a_{m+1}=\frac{m+1}{2} ,令 i 为偶数则 am+1=m+12a_{m+1}=\frac{m+1}{2} 。可以看出,无论 m + 1 为奇数还是偶数,只要令 i 为奇数就可以使 am+1a_{m+1} 取得最大值,且满足am+1=m+12a_{m+1} = ⌈\frac{m+1}{2}⌉

由此得证,Pn=n2/nP_n=⌈\frac{n}{2}⌉/n

代码实现

得到上面的结论,代码就可以写得很简短了。

std::string solution(int n) {
    if(n == 1) return "1.00000";
    int result = ((n + 1) / 2 * 1000000 / n + 5) / 10;
    return "0." + std::to_string(result % 100000);
}

除了 n=1n=1 时概率为 1 ,其余情况下概率都是小于 1 的。用整型来计算小数点后数字, (n + 1) / 2 是计算 n2⌈\frac{n}{2}⌉ , (x * 1000000 / n + 5) / 10 是四舍五入保留五位。

复杂度分析

数学推理复杂度 \uparrow \uparrow \uparrow

代码复杂度O(1)