转自法力无边的厚白书。
题意:给出一个n个数的序列,两个人轮流从左端或右端开始取任意数。求第一人的数减去第二个人的最大值。
这一题,我们考虑从左边取还是从右边取,取多少个数。可以枚举每个状态。
dp[l[[r],表示从l到r,最大可以得到的数。它可以由dp[k][r], dp[l][m]得来,k = l + 1---> r m = l ---- >r - 1。k和m相当于枚举取 1 -> n - 1个数的所有情况,也就是省下的数被取的情况,也就是另一个人取的最好情况。如果另一个人的最好情况大于0,那么就取完,如果小于0,那么就按照最优解的情况取。如何取完,需要m = 0。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100 + 5;
int dp[maxn][maxn], num[maxn], sum[maxn];
bool vis[maxn][maxn];
int DP(int l, int r)
{
if(vis[l][r]) return dp[l][r];
vis[l][r] = 1;
int m = 0;//能使甚至取完所有数
for(int k = l + 1; k <= r; k++)
m = min(m, DP(k, r));
for(int k = l; k < r; k++)
m = min(m, DP(l, k));
dp[l][r] = sum[r] - sum[l - 1] - m;
//printf("%d %d %d\n", m, l, r);
return dp[l][r];
}
int main()
{
int n;
sum[0] = 0;
while(scanf("%d", &n) == 1 && n)
{
//memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
sum[i] = sum[i - 1] + num[i];
}
printf("%d\n", 2 * DP(1, n) - sum[n]);//ans = DP(1, n) - ( sum[n] - DP(1, n) )
}
return 0;
}