HihoCoder1338 A Game (区间DP)
<题目链接>
题目大意:
两个人轮流从一个序列中取数,他们都面临同样的二选一决策:是拿走最左边的数,还是拿走最右边的数?问先手最多能够得到的分数是多少。
解题分析:
一道比较经典的DP,因为每次只能从数组的两端取走一个数,所以每次面对的数组都只可能是一段连续的子数组。我们不妨假设$dp[l][r]$表示对于数组$A[i]~A[j]$,先手能够获得的最多得分。于是状态的转移就不难得出了。
枚举所有区间:
$l==r$的时候,肯定是$dp[l][r]=arr[l]$
而对于其他区间大于1的情况,$dp[l][r]=max(dp[l][r],((sum[r]-sum[l-1])-min(dp[l+1][r],dp[l][r-1])))$
官方题解 >>>
递推DP
#include <bits/stdc++.h> using namespace std; #define N int(1e3+5) int n,dp[N][N],arr[N],sum[N]; int main(){ scanf("%d",&n); sum[0]=0; for(int i=1;i<=n;i++)scanf("%d",&arr[i]),sum[i]=sum[i-1]+arr[i]; memset(dp,-0x3f,sizeof(dp)); for(int i=n;i>=1;i--){ dp[i][i]=arr[i]; for(int j=i+1;j<=n;j++){ dp[i][j]=max(dp[i][j],(sum[j]-sum[i-1])-min(dp[i+1][j],dp[i][j-1])); } } printf("%d\n",dp[1][n]); }
记忆化搜索
#include <bits/stdc++.h> using namespace std; const int N = 1e3+5; int n,arr[N],dp[N][N],sum[N]; int DP(int l,int r){ if(l>r)return 0; if(dp[l][r]!=-1)return dp[l][r]; dp[l][r]=-1e9; if(l==r)dp[l][r]=arr[l]; else dp[l][r]=max(dp[l][r],(sum[r]-sum[l-1])-min(DP(l+1,r),DP(l,r-1))); return dp[l][r]; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&arr[i]),sum[i]=sum[i-1]+arr[i]; } memset(dp,-1,sizeof(dp)); printf("%d\n",DP(1,n)); }
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。