“题目解析#203 | 豆包MarsCode AI 刷题”

58 阅读4分钟

小Q和小X的游戏:胜率分析

在程序设计和算法分析的学习中,我们经常碰到类似的博弈论问题。这道题目以小Q和小X的游戏形式呈现,涉及到动态规划和概率计算,我们需要从博弈的角度去理解和分析。在这个游戏中,两位玩家交替移动,目的是选择左边比当前元素更小的元素。如果一位玩家无法进行合法移动,则他将输掉游戏。以下是对题目解读、思考和代码解析的详细分析。

问题解读

小Q和小X玩的是基于给定数组的选择游戏。每次一个玩家必须选择一个比当前元素小的元素,并移动到该元素的索引上。游戏的基本规则导致了一个重要的观念:若玩家在某个状态下没有合法移动,就会输掉游戏。因此,游戏的结果不仅仅依赖于当前的选择,还要考虑后续可能的选择和对手的反应。

我们的目标是计算小Q在采取最优策略的情况下获胜的概率,并返回其简化的分数形式。为了达到这个目标,我们可以通过动态规划技术设计求解方案,下面将进行详细的分析。

动态规划思路

动态规划的本质是将复杂问题分解为简单的子问题,进而组合解决方案。对于这个题目,我们定义一个数组 dp,其中 dp[i] 表示从索引 i 开始小Q的胜率。我们的计算过程如下:

  1. 建立状态转移方程

    • 首先,我们需要找出当前元素 a[i] 左侧比其更小的所有元素的索引,记为 less_than_next[i]
    • 如果 less_than_next[i] 为空,说明小Q无法进行合法移动,因此 dp[i] = 0
    • 否则,我们需要统计小Q可以进行的所有移动概率。对于每一个合法移动到 next_index,我们需要计算对手在该状态下的胜率,从而推导出小Q在 i 状态的胜率。
  2. 计算胜率

    • 对于每一个可以移动的状态,累加概率时,我们需要考虑小X的胜率,即 1 - dp[next_index]
    • 最终胜率计算为所有可能移动的胜率的平均值。

代码实现

给定上述分析,我们可以实现以下代码:

python

from fractions import Fraction

def solution(n, a):
    dp = [0] * n  # dp[i] 表示从索引 i 开始小Q的胜率
    less_than_next = [[] for _ in range(n)]  # less_than_next[i] 存储小于 a[i] 的元素的索引

    # 填充 less_than_next
    for i in range(n):
        for j in range(i):
            if a[j] < a[i]:
                less_than_next[i].append(j)

    # 计算胜率
    for i in range(n - 1, -1, -1):
        if not less_than_next[i]:
            dp[i] = 0  # 没有合法移动,必败
            continue

        total_prob = 0  # 总概率
        total_moves = len(less_than_next[i])  # 合法移动的数量

        for next_index in less_than_next[i]:
            total_prob += (1 - dp[next_index]) / total_moves  # 累加赢得的概率

        dp[i] = total_prob  # 当前状态的胜率

    # 计算小Q的最终胜率
    total_win_prob = 0
    for prob in dp:
        total_win_prob += prob

    total_win_prob /= n  # 取所有起点的平均胜率

    # 将概率转成最简分数
    final_prob = Fraction(total_win_prob).limit_denominator()
    return f"{final_prob.numerator}/{final_prob.denominator}"

个人思考与总结

通过动态规划的思路,我们有效地解决了看似复杂的博弈问题,掌握了从多个状态转移的方式计算胜率的技巧。我认为在解析博弈问题时,尤其是在对抗性游戏中,理解当前状态及其可能转移是至关重要的。此外,这让我意识到在许多算法问题中,清晰的状态定义和转移方程是提高解题效率的关键。

在实际应用中,这种模型不仅适用于此类游戏问题,广泛的动态规划技术与博弈论结合的实例也有许多,比如“石子游戏”、“月光宝盒问题”等。这些问题的解法往往依赖于对状态和转移过程的透彻理解。

总之,学习算法和数据结构不仅是掌握处理能力,更是一种解决问题的思维方式,通过这样的训练,我们可以提升自己的逻辑思维及解决复杂问题的能力。