返回

秋招攻略-最速、最鲜的 LeetCode刷题攻略!

后端

巧解 LeetCode 1406:动态规划助力博弈论

前言

博弈论在计算机科学中有着广泛的应用,而 LeetCode 1406 则是考察博弈论的一道经典题目。本文将深入解析这道题,带领大家一步步领悟动态规划的奥秘,从而轻松破解博弈论难题。

题目简介

在 LeetCode 1406 中,我们给定一个数组,其中包含一系列整数。两位玩家 Alice 和 Bob 轮流从数组中取元素,每次可以取 1、2 或 3 个元素,并将其对应的值累加到自己的总和中。先手玩家为 Alice,最终谁获得的总和更大,谁就获胜。如果总和相等,则 Bob 获胜。

动态规划解法

这道题的关键在于动态规划,即通过逐步求解子问题,最终得到整个问题的最优解。

我们定义 dp[i] 为从数组下标 i 到数组末尾的元素所能获得的最大总和。

对于 Alice 而言,她会优先取能让自己获得更大总和的子区间。因此,dp[i] 可以由以下三种情况得到:

  • 取前 1 个元素:dp[i] = max(dp[i + 1], dp[i + 2], dp[i + 3])
  • 取前 2 个元素:dp[i] = max(dp[i + 2], dp[i + 3], dp[i + 4]) + arr[i]
  • 取前 3 个元素:dp[i] = max(dp[i + 3], dp[i + 4], dp[i + 5]) + arr[i] + arr[i + 1]

对于 Bob 而言,他希望自己的总和尽可能小,让 Alice 无法超越。因此,dp[i] 可以由以下三种情况得到:

  • 取前 1 个元素:dp[i] = min(dp[i + 1], dp[i + 2], dp[i + 3])
  • 取前 2 个元素:dp[i] = min(dp[i + 2], dp[i + 3], dp[i + 4]) - arr[i]
  • 取前 3 个元素:dp[i] = min(dp[i + 3], dp[i + 4], dp[i + 5]) - arr[i] - arr[i + 1]

代码实现

def max_sum(arr):
    n = len(arr)
    dp = [0] * n
    dp[n - 1] = arr[n - 1]
    for i in range(n - 2, -1, -1):
        dp[i] = max(dp[i + 1], dp[i + 2], dp[i + 3]) + arr[i]
    return dp[0]

def min_sum(arr):
    n = len(arr)
    dp = [0] * n
    dp[n - 1] = arr[n - 1]
    for i in range(n - 2, -1, -1):
        dp[i] = min(dp[i + 1], dp[i + 2], dp[i + 3]) - arr[i]
    return dp[0]

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
max_sum = max_sum(arr)
min_sum = min_sum(arr)
if max_sum > min_sum:
    print("Alice 获胜")
elif max_sum == min_sum:
    print("Bob 获胜")
else:
    print("Bob 获胜")

总结

通过动态规划的思想,我们将 LeetCode 1406 问题分解为一系列子问题,并逐步求解,最终得到数组所能获得的最大总和。本题不仅考察了博弈论的策略思考,更体现了动态规划的强大求解能力。

常见问题解答

  1. 什么是动态规划?

动态规划是一种解决复杂问题的方法,将问题分解为一系列重叠子问题,逐步求解,并将子问题的解存储起来,避免重复计算,从而高效求解全局最优解。

  1. 如何使用动态规划解决 LeetCode 1406 问题?

通过定义子问题的状态 dp[i] ,并根据不同的取法进行状态转移,最终从 dp[0] 中得到数组所能获得的最大总和。

  1. 为什么 Alice 先手不一定能获胜?

因为 Bob 是一个最优策略的玩家,他会选择让 Alice 获得的总和尽可能小,从而让自己获胜。

  1. 如何判断 Alice 和 Bob 谁获胜?

比较 Alice 和 Bob 获得的最大总和,如果 Alice 大于 Bob,则 Alice 获胜,如果相等则 Bob 获胜。

  1. 代码中的 ** arr[i] 是什么意思?**

arr[i] 表示数组下标 i 处的元素值。