【2024GXOI进阶】分糖果(candy) 博弈论dp

分糖果博弈问题解题思路与代码注释

解题思路

  1. 问题分析

    • 这是一个双人轮流取糖果的博弈问题

    • 两人都采取最优策略,目标是使自己获得的总糖果数最多

    • 每次只能取最左边的糖果包,选择给自己或对方

    • 分配权会转移到本次未获得糖果的人手中

  2. 关键观察

    • 可以使用动态规划来解决,从后向前计算最优解

    • 定义f[i]表示从第i包到第n包糖果时,当前玩家能比对手多获得的最大糖果数

    • 状态转移方程:f[i] = max(a[i] - f[i+1], f[i+1] - a[i])

      • 第一种情况:当前玩家取第i包,对手从i+1开始能比当前玩家多f[i+1]

      • 第二种情况:当前玩家不取第i包,对手取第i包,当前玩家从i+1开始能比对手多f[i+1]

  3. 结果计算

    • 总糖果数为sum

    • 最终小林比小伊多的糖果数为f[0]

    • 小林获得的糖果数为(sum + f[0])/2

#include<bits/stdc++.h>
#define ll long long  // 定义long long类型简写
using namespace std;
const int N = 1e5 + 10;  // 定义最大糖果包数
int n, a[N], f[N];       // n-糖果包数,a-糖果数量数组,f-DP数组
ll sum;                  // 所有糖果总数

int main()
{
    cin >> n;  // 输入糖果包数
    for(int i = 1; i <= n; i++) {
        cin >> a[i];      // 输入每包糖果数量
        sum += a[i];     // 计算总糖果数
    }
    
    // 从后向前动态规划计算
    for(int i = n; i >= 0; i--) {
        // 状态转移方程:
        // 当前玩家可以选择取或不取第i包糖果
        // 取:a[i] - f[i+1] (获得a[i],但对手在i+1后能比玩家多f[i+1])
        // 不取:f[i+1] - a[i] (对手获得a[i],玩家在i+1后能比对手多f[i+1])
        f[i] = max(a[i] - f[i + 1], f[i + 1] - a[i]);
    }
    
    // 计算最终结果:(总糖果 + 小林比小伊多的糖果)/2 = 小林获得的糖果
    ll ans = (sum + f[0]) / 2;
    cout << ans;
    
    return 0;
}

为什么 a[i] - dp[i+1] 是自己拿的净收益?

  1. 自己拿第 i 包

    • 当前玩家获得 a[i] 糖果。

    • 对手没有拿到糖果,因此分配权转移给对手

    • 对手在剩下的 i+1 到 n 包糖果中会采取最优策略,获得比当前玩家多 dp[i+1] 的糖果(因为 dp[i+1] 是从 i+1 开始时的差值,此时对手是“当前玩家”)。

    • 因此,当前玩家的净收益是:

      自己拿的 �[�]−对手后续的净收益 ��[�+1]自己拿的a[i]对手后续的净收益dp[i+1]
    • 即 a[i] - dp[i+1]

  2. 举例说明
    假设剩余糖果为 [5, 7, 9],当前玩家是小林:

    • 小林拿 5:获得 5,分配权转给小伊。

    • 小伊面对 [7, 9] 时,会通过最优策略获得比小林多 dp[i+1] 的糖果(假设 dp[i+1]=2)。

    • 小林的净收益是 5 - 2 = 3


为什么 -a[i] + dp[i+1] 是让对方拿的净收益?

  1. 让对方拿第 i 包

    • 对手获得 a[i] 糖果。

    • 当前玩家没有拿到糖果,因此分配权仍归自己

    • 当前玩家在剩下的 i+1 到 n 包糖果中继续作为“当前玩家”,能获得比对手多 dp[i+1] 的糖果。

    • 因此,当前玩家的净收益是:

    • 即 -a[i] + dp[i+1]

  2. 举例说明
    继续 [5, 7, 9] 的例子:

    • 小林让小伊拿 5:小伊获得 5,分配权仍归小林。

    • 小林面对 [7, 9] 时,能通过最优策略获得比小伊多 dp[i+1] 的糖果(假设 dp[i+1]=2)。

    • 小林的净收益是 -5 + 2 = -3(此时小伊总收益更多)。


为什么取 max

当前玩家会选择对自己更有利的策略:

  • 自己拿:净收益 a[i] - dp[i+1]

  • 对方拿:净收益 -a[i] + dp[i+1]
    选择两者中的最大值,即:

dp[i]=max(a[i]dp[i+1],a[i]+dp[i+1])

 
 

为什么需要倒序遍历动态规划数组 dp

在解决这个分糖果的博弈问题时,我们使用动态规划(DP)来记录从第 i 包到第 n 包糖果时,当前拥有分配权的玩家能比对手多获得的糖果数。关键在于理解 dp[i] 依赖于 dp[i+1],即当前状态依赖于后续状态。以下是详细解释:


1. 依赖关系:当前状态需要知道后续状态的结果

  • 定义dp[i] 表示从第 i 包到第 n 包糖果时,当前玩家的最大净收益。

  • 依赖:为了计算 dp[i],我们需要知道 dp[i+1](即从第 i+1 包到第 n 包的结果),因为当前玩家的选择会影响后续的分配权归属和收益。

    • 如果自己拿第 i 包,对手会在 i+1 到 n 包中采取最优策略(即 dp[i+1] 是对手的净收益)。

    • 如果让对方拿第 i 包,自己会在 i+1 到 n 包中继续作为当前玩家(即 dp[i+1] 是自己的净收益)。

  • 结论dp[i] 的计算必须基于 dp[i+1],因此需要先计算 dp[i+1],再计算 dp[i]。这就是倒序遍历的原因。

  •  
posted @ 2025-05-08 21:33  CRt0729  阅读(89)  评论(0)    收藏  举报