题意: 有一个长度n的整数序列,两个人A和B轮流取数,A先,每次只能从左端或者右端取任意数量个数,所有数取完后,统计A和B取走的数之和,假设A和B都足够聪明,求A的得分-B的得分
题解:根据蓝书讲解,可以用dp[i][j]表示区间i-j上,两人都采取最佳策略,先手获得分的最高值。
则 dp[i][j] = sum(i,j) - min{dp[i][i],dp[i][i+1]...,dp[i+1][j],dp[i+2][j]..0}
意思就是枚举先手取数的情况,例如只取i,则dp[i+1][j]表示另外一个人能拿到的最大值,用sum(i,j)一减,就是先手获得的值然后所有情况找最大值,就是最优策略
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 1e17
typedef long long ll;
int n;
int a[110];
ll dp[110][110];
ll Sum[110];
int main() {
while(scanf("%d",&n) == 1 && n) {
memset(dp,0,sizeof(dp));
memset(Sum,0,sizeof(Sum));
for(int i = 0;i < n;i++) {
scanf("%d",&a[i]);
Sum[i] = (i==0?a[i]:(a[i]+Sum[i-1]));
}
for(int i = 0;i < n;i++)
for(int j = i;j < n;j++)
dp[i][j] = -INF;
for(int i = 0;i < n;i++)
dp[i][i] = a[i];
for(int w = 2;w <= n;w++)
for(int i = 0;i < n;i++) {
int j = i+w-1;
if(j >= n) break;
ll t = 0;
for(int k = i;k < j;k++)
t = min(t,dp[i][k]);
for(int k = j;k > i;k--)
t = min(t,dp[k][j]);
ll s = Sum[j] - (i==0?0:Sum[i-1]);
dp[i][j] = s - t;
}
printf("%lld\n",dp[0][n-1]-(Sum[n-1]-dp[0][n-1]));
}
return 0;
}