【2024GXOI进阶】分糖果(candy) 博弈论dp
分糖果博弈问题解题思路与代码注释
解题思路
- 
问题分析: - 
这是一个双人轮流取糖果的博弈问题 
- 
两人都采取最优策略,目标是使自己获得的总糖果数最多 
- 
每次只能取最左边的糖果包,选择给自己或对方 
- 
分配权会转移到本次未获得糖果的人手中 
 
- 
- 
关键观察: - 
可以使用动态规划来解决,从后向前计算最优解 
- 
定义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] 
 
- 
 
- 
- 
结果计算: - 
总糖果数为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] 是自己拿的净收益?
- 
自己拿第 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]。
 
- 
- 
举例说明: 
 假设剩余糖果为[5, 7, 9],当前玩家是小林:- 
小林拿 5:获得5,分配权转给小伊。
- 
小伊面对 [7, 9]时,会通过最优策略获得比小林多dp[i+1]的糖果(假设dp[i+1]=2)。
- 
小林的净收益是 5 - 2 = 3。
 
- 
为什么 -a[i] + dp[i+1] 是让对方拿的净收益?
- 
让对方拿第 i包:- 
对手获得 a[i]糖果。
- 
当前玩家没有拿到糖果,因此分配权仍归自己。 
- 
当前玩家在剩下的 i+1到n包糖果中继续作为“当前玩家”,能获得比对手多dp[i+1]的糖果。
- 
因此,当前玩家的净收益是: 
- 
即 -a[i] + dp[i+1]。
 
- 
- 
举例说明: 
 继续[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]。这就是倒序遍历的原因。
- 
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号