题目大意:从一个序列两端取数,先后手两人
均采用最优策略,问先后手的得分。
题解:
区间dp
如果先手面临的状态是a1,a2,a3,a4,a5.
如果取走一个那么后手面临的状态是a2,a3,a4,a5、
同样也是一个最优值。
f[l][r]表示选手A面临[l,r]状态的最优值,那么选手B的最优值
就是区间[l,r]的区间和-f[l][r].
记忆化搜索用结构体返回两个玩家的得分
代码:
#include<iostream> #include<cstdio> #include<cstring> #define N 220 using namespace std; int n; int a[N],sum[N],f[N][N]; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i],f[i][i]=a[i]; for(int len=2;len<=n;len++){ for(int l=1;l+len-1<=n;l++){ int r=l+len-1; f[l][r]=max(sum[r]-sum[l-1]-f[l+1][r],sum[r]-sum[l-1]-f[l][r-1]); } } printf("%d %d",f[1][n],sum[n]-f[1][n]); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #define N 220 using namespace std; int n; int a[N],sum[N],dp[N][N]; struct Score{ int p0,p1; }; Score dfs(int l,int r,int p){ if(l==r){ if(p)return (Score){0,a[l]}; return (Score){a[l],0}; } if(dp[l][r]){ if(p) return (Score){sum[r]-sum[l-1]-dp[l][r],dp[l][r]}; return (Score){dp[l][r],sum[r]-sum[l-1]-dp[l][r]}; } if(p){ dp[l][r]=max(dfs(l+1,r,0).p1+a[l],dfs(l,r-1,0).p1+a[r]); return (Score){sum[r]-sum[l-1]-dp[l][r],dp[l][r]}; }else{ dp[l][r]=max(dfs(l+1,r,1).p0+a[l],dfs(l,r-1,1).p0+a[r]); return (Score){dp[l][r],sum[r]-sum[l-1]-dp[l][r]}; } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i]; Score ans=dfs(1,n,0); printf("%d %d ",ans.p0,ans.p1); return 0; }