uva 10891 区间dp+记忆化搜索

https://vjudge.net/problem/UVA-10891

给定一个序列x,A和B依次取数,规则是每次只能从头或者尾部取走若干个数,A和B采取的策略使得自己取出的数尽量和最大,A是先手,求最后A-B的得分。

令 f(i,j)表示对于[i,j]对应的序列,先手可以从中获得的最大得分,那么答案可以写为  f(i,j)-(sum(i,j)-f(i,j)),也就是 2*f(i,j)-sum(i,j)

下面讨论f(i,j)的写法,显然递归的形式更好表达一些,为了防止重复的计算使用记忆化搜索。

当(i==j)时显然返回a[i]即可;

否则,我们可以枚举出所有先手可能拿走的数的区间,得出一个最大值就是返回值。

方程就是  f(i,j)=MAX{sum(i,k)+sum(K+1,j)-f(k+1,j) , sum(k,j)+sum(i,k-1)-f(i,k-1) | i<=k<=j};  //[i,k]和[k,j]是先手可能取得区间

还有一个转移方程是  f(i,j)=sum(i,j)-MIN(f(k1,k2)) | [k1,k2]是先手可能取得区间对应的补集。

 #include<bits/stdc++.h>
using namespace std;
int pre[],a[];
int ans[][],vis[][];
int sum(int i,int j)
{
if(i>j) return ;
return pre[j]-pre[i-];
}
int f(int l,int r)
{
if(l>r) return ;
if(vis[l][r]) return ans[l][r];
vis[l][r]=;
if(l==r) return ans[l][r]=a[l];
int ret=-;
for(int k=l;k<=r;++k)
{
ret=max(ret,max(sum(l,k)+sum(k+,r)-f(k+,r),sum(k,r)+sum(l,k-)-f(l,k-)));
}
return ans[l][r]=ret;
}
int main()
{
int N,m,i,j,k;
while(cin>>N&&N){
memset(vis,,sizeof(vis));
for(i=;i<=N;++i)
{
cin>>a[i];
pre[i]=pre[i-]+a[i];
}
cout<<*f(,N)-pre[N]<<endl;
}
return ;
}
上一篇:android studio adb.exe已停止工作(全面成功版 进程的查询和开启)


下一篇:(区间dp + 记忆化搜索)Treats for the Cows (POJ 3186)