1 条题解
-
0
#include<bits/stdc++.h> using namespace std; // [1] n-财宝的件数;arr数组-存储每件财宝的价值(下标1~n);brr数组-前缀和数组,brr[i]表示前i件财宝的价值和 int n,arr[5100],brr[5100]={}; // [2] dp[l][r]-区间[l, r]内,当前玩家能获得的最大收益(双方均采取最优策略) int dp[5100][5100]={}; int main(){ // 问题分析:区间DP问题,两人轮流拿当前区间两端的财宝,均采取最优策略,求先手Jack的最大收益 // 解题步骤:1.计算前缀和数组,快速获取任意区间的价值和;2.初始化长度为1的区间(只有1件财宝时,当前玩家直接获得); // 3.按区间长度从小到大动态规划:对于区间[l, r],当前玩家拿左或右后,剩下的区间由对方最优选择,当前玩家收益=区间和-对方在剩余区间的收益; // 4.最终dp[1][n]即为Jack的最大收益 cin>>n; int sum=0; for(int i=1;i<=n;i++){ cin>>arr[i]; brr[i]=brr[i-1]+arr[i]; // [3] 计算前缀和:前i件财宝的价值和 = 前i-1件的和 + 当前件的价值 } // 1. 初始化:长度为1的区间(只有1件财宝),当前玩家直接获得该财宝的价值 for(int i=1;i<=n;i++) dp[i][i]=arr[i]; // 区间DP核心循环:按区间长度从小到大计算(len为区间长度,从2到n) for(int len=2;len<=n;len++){ // 遍历所有长度为len的区间的左端点l for(int l=1;l+len-1<=n;l++){ int r=l+len-1; // [4] 计算当前区间的右端点r // 2. 计算当前区间[l, r]的总价值 int ans=brr[r]-brr[l-1]; // 状态转移:当前玩家有两种选择(拿左端点l或右端点r) // 拿左端点后,剩下的区间是[l+1, r],对方在该区间的最优收益为dp[l+1][r] // 拿右端点后,剩下的区间是[l, r-1],对方在该区间的最优收益为dp[l][r-1] // 当前玩家的收益 = 区间总价值 - 对方在剩余区间的最优收益(因为对方会最大化自己的收益,即最小化当前玩家的收益) dp[l][r]=ans-min(dp[l][r-1],dp[l+1][r]); } } cout<<dp[1][n]; // [5] 输出整个区间[1, n]的最优收益,即Jack的最大收益 return 0; }
- 1
信息
- ID
- 1346
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者