石子游戏 VII(博弈类区间DP)
字数 1974 2025-11-14 09:31:20

石子游戏 VII(博弈类区间DP)

题目描述:
有一排石子堆排成一行,每个石子堆有一个对应的价值数组 stones,其中 stones[i] 表示第 i 堆石子的价值。两名玩家(Alice 和 Bob)轮流进行游戏,Alice 先手。在每一轮中,玩家可以从当前剩余石子堆的最左端或最右端移除一堆石子,并获得相应的分数。玩家的得分是他移除石子堆价值的总和。游戏的目标是最大化自己的得分差值。假设两位玩家都采用最优策略,请返回 Alice 能够取得的最高得分差值。

解题过程:

我们使用动态规划来解决这个问题。定义 dp[i][j] 表示当剩余石子堆为 stones[i...j] 时,当前玩家(不一定是 Alice)可以比对手多得的分数。

状态转移方程:
当轮到当前玩家时,他有两种选择:

  1. 移除最左边的石子堆 stones[i],那么他会获得 stones[i] 的分数,然后轮到对手在 stones[i+1...j] 上操作。此时对手会比当前玩家多 dp[i+1][j] 分,所以当前玩家比对手多 stones[i] - dp[i+1][j] 分。
  2. 移除最右边的石子堆 stones[j],那么他会获得 stones[j] 的分数,然后轮到对手在 stones[i...j-1] 上操作。此时对手会比当前玩家多 dp[i][j-1] 分,所以当前玩家比对手多 stones[j] - dp[i][j-1] 分。

由于当前玩家会选择对自己更有利的操作,所以:
dp[i][j] = max(stones[i] - dp[i+1][j], stones[j] - dp[i][j-1])

边界条件:
当 i = j 时,即只剩下一堆石子,当前玩家移除它,获得 stones[i] 分,对手得 0 分,所以 dp[i][i] = stones[i]。

具体步骤:

  1. 初始化一个 n×n 的 dp 数组,其中 n 是石子堆的数量。
  2. 按区间长度从小到大进行遍历:
    • 长度为 1:dp[i][i] = stones[i]
    • 长度从 2 到 n:
      对于每个起始位置 i,计算结束位置 j = i + len - 1
      dp[i][j] = max(stones[i] - dp[i+1][j], stones[j] - dp[i][j-1])
  3. 最终结果存储在 dp[0][n-1] 中,表示 Alice 先手时能比 Bob 多得的分数。

示例验证:
假设 stones = [5,3,1,4,2]
计算过程:

  • 长度为1:dp[0][0]=5, dp[1][1]=3, dp[2][2]=1, dp[3][3]=4, dp[4][4]=2
  • 长度为2:
    dp[0][1] = max(5-dp[1][1], 3-dp[0][0]) = max(5-3, 3-5) = max(2,-2) = 2
    dp[1][2] = max(3-1, 1-3) = max(2,-2) = 2
    dp[2][3] = max(1-4, 4-1) = max(-3,3) = 3
    dp[3][4] = max(4-2, 2-4) = max(2,-2) = 2
  • 长度为3:
    dp[0][2] = max(5-dp[1][2], 1-dp[0][1]) = max(5-2, 1-2) = max(3,-1) = 3
    dp[1][3] = max(3-dp[2][3], 4-dp[1][2]) = max(3-3, 4-2) = max(0,2) = 2
    dp[2][4] = max(1-dp[3][4], 2-dp[2][3]) = max(1-2, 2-3) = max(-1,-1) = -1
  • 长度为4:
    dp[0][3] = max(5-dp[1][3], 4-dp[0][2]) = max(5-2, 4-3) = max(3,1) = 3
    dp[1][4] = max(3-dp[2][4], 2-dp[1][3]) = max(3-(-1), 2-2) = max(4,0) = 4
  • 长度为5:
    dp[0][4] = max(5-dp[1][4], 2-dp[0][3]) = max(5-4, 2-3) = max(1,-1) = 1

最终 Alice 能比 Bob 多得 1 分。

这个解法的时间复杂度是 O(n²),空间复杂度也是 O(n²),通过自底向上的方式填充 dp 表,确保了我们能够正确计算每个子区间的最优解。

石子游戏 VII(博弈类区间DP) 题目描述: 有一排石子堆排成一行,每个石子堆有一个对应的价值数组 stones,其中 stones[ i ] 表示第 i 堆石子的价值。两名玩家(Alice 和 Bob)轮流进行游戏,Alice 先手。在每一轮中,玩家可以从当前剩余石子堆的最左端或最右端移除一堆石子,并获得相应的分数。玩家的得分是他移除石子堆价值的总和。游戏的目标是最大化自己的得分差值。假设两位玩家都采用最优策略,请返回 Alice 能够取得的最高得分差值。 解题过程: 我们使用动态规划来解决这个问题。定义 dp[ i][ j] 表示当剩余石子堆为 stones[ i...j ] 时,当前玩家(不一定是 Alice)可以比对手多得的分数。 状态转移方程: 当轮到当前玩家时,他有两种选择: 移除最左边的石子堆 stones[ i],那么他会获得 stones[ i] 的分数,然后轮到对手在 stones[ i+1...j] 上操作。此时对手会比当前玩家多 dp[ i+1][ j] 分,所以当前玩家比对手多 stones[ i] - dp[ i+1][ j ] 分。 移除最右边的石子堆 stones[ j],那么他会获得 stones[ j] 的分数,然后轮到对手在 stones[ i...j-1] 上操作。此时对手会比当前玩家多 dp[ i][ j-1] 分,所以当前玩家比对手多 stones[ j] - dp[ i][ j-1 ] 分。 由于当前玩家会选择对自己更有利的操作,所以: dp[ i][ j] = max(stones[ i] - dp[ i+1][ j], stones[ j] - dp[ i][ j-1 ]) 边界条件: 当 i = j 时,即只剩下一堆石子,当前玩家移除它,获得 stones[ i] 分,对手得 0 分,所以 dp[ i][ i] = stones[ i ]。 具体步骤: 初始化一个 n×n 的 dp 数组,其中 n 是石子堆的数量。 按区间长度从小到大进行遍历: 长度为 1:dp[ i][ i] = stones[ i ] 长度从 2 到 n: 对于每个起始位置 i,计算结束位置 j = i + len - 1 dp[ i][ j] = max(stones[ i] - dp[ i+1][ j], stones[ j] - dp[ i][ j-1 ]) 最终结果存储在 dp[ 0][ n-1 ] 中,表示 Alice 先手时能比 Bob 多得的分数。 示例验证: 假设 stones = [ 5,3,1,4,2 ] 计算过程: 长度为1:dp[ 0][ 0]=5, dp[ 1][ 1]=3, dp[ 2][ 2]=1, dp[ 3][ 3]=4, dp[ 4][ 4 ]=2 长度为2: dp[ 0][ 1] = max(5-dp[ 1][ 1], 3-dp[ 0][ 0 ]) = max(5-3, 3-5) = max(2,-2) = 2 dp[ 1][ 2 ] = max(3-1, 1-3) = max(2,-2) = 2 dp[ 2][ 3 ] = max(1-4, 4-1) = max(-3,3) = 3 dp[ 3][ 4 ] = max(4-2, 2-4) = max(2,-2) = 2 长度为3: dp[ 0][ 2] = max(5-dp[ 1][ 2], 1-dp[ 0][ 1 ]) = max(5-2, 1-2) = max(3,-1) = 3 dp[ 1][ 3] = max(3-dp[ 2][ 3], 4-dp[ 1][ 2 ]) = max(3-3, 4-2) = max(0,2) = 2 dp[ 2][ 4] = max(1-dp[ 3][ 4], 2-dp[ 2][ 3 ]) = max(1-2, 2-3) = max(-1,-1) = -1 长度为4: dp[ 0][ 3] = max(5-dp[ 1][ 3], 4-dp[ 0][ 2 ]) = max(5-2, 4-3) = max(3,1) = 3 dp[ 1][ 4] = max(3-dp[ 2][ 4], 2-dp[ 1][ 3 ]) = max(3-(-1), 2-2) = max(4,0) = 4 长度为5: dp[ 0][ 4] = max(5-dp[ 1][ 4], 2-dp[ 0][ 3 ]) = max(5-4, 2-3) = max(1,-1) = 1 最终 Alice 能比 Bob 多得 1 分。 这个解法的时间复杂度是 O(n²),空间复杂度也是 O(n²),通过自底向上的方式填充 dp 表,确保了我们能够正确计算每个子区间的最优解。