大意不再赘述。
思路:
经典的区间DP,于是利用d[i][j]表示当前A在区间i~j内取得的最大数,决策是取1~j-k+1个数,那么状态转移方程即可表示为:
d[i][j] = max(d[i][j], Sum(i, j)-min(dp(i+k, j), dp(i, j-k)));
表示在i~j内A能取得的最大数,由于许多重复子问题的存在,可以选用记忆化搜索,注意边界问题。
答案即是:d[1][n] - (Sum[1][n] - d[1][n]);前者表示A在1~n取得的最大值,后者表示B在1~n取得的最大值。
初始化d[i][i] = A[i]可要可不要,表示在区间i~i内,能取的最大值为A[i]。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int n;
int A[MAXN];
int d[MAXN][MAXN];
bool vis[MAXN][MAXN];
int Sum(int x, int y)
{
int s = 0;
for(int i = x; i <= y; i++) s += A[i];
return s;
}
void init()
{
memset(vis, 0, sizeof(vis));
}
int read_case()
{
init();
scanf("%d", &n);
if(!n) return 0;
for(int i = 1; i <= n; i++) scanf("%d", &A[i]);
return 1;
}
int dp(int i, int j)
{
int &ans = d[i][j];
if(i > j) return 0;
if(vis[i][j]) return ans;
vis[i][j] = 1;
ans = -INF;
for(int k = 1; k <= j-i+1; k++) //当前决策
{
ans = max(ans, Sum(i, j)-min(dp(i+k, j), dp(i, j-k)));
}
return ans;
}
void solve()
{
int ans = dp(1, n) - (Sum(1, n) - dp(1, n));
printf("%d\n", ans);
}
int main()
{
while(read_case())
{
solve();
}
return 0;
}