虽然这道题不算很难,但却是很多地方值得琢磨。
第一次遇到关于博弈论的题目一开始还是没有思路的。
后来是想到关于求最优解一般都是dp,然后往哪个方向去想,就想到了可以用区间dp的方式。
我们以dp[i][j]来表示,a先手能取得的最大值。
那么 至少每个区间i-j的总和不变,要使得dp最大,那么要另外一方最小(而且要保证另一方也是最优解)。
dp[i][j]=max(sum(i,j)-min(dp[i][k],dp[k+1][j]);
可以想到,如果要让a在这个区间内去的最小,那么要b,从i-k或者j-k+1取得最小才行,
而每个人又尽量取得最大值,那么可以认为当b先手时要最大,但这个最大的要取所有 最大值中间最小的那个,这样才能使dp[i][j]最大。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
int n;
int a[102];
int sum[102];
int d[102][102];
int inf = INT_MIN;
//代码不难主要是思想可以很好的借鉴一下
int dp(int a,int b)
{
int &ans = d[a][b];
if (ans != inf)return ans;
//if (a > b) return 0;
ans = sum[b]-sum[a-1];//初始化成区间长度
up(i, a, b)
{
d[a][b] = max(d[a][b],sum[b] - sum[a-1] -min(dp(a, i), dp(i + 1, b)));//区间dp
}
return ans;
}
int main()
{
while (cin >> n && n)
{
sum[0] = 0;
upd(i, 1, n)
{
cin >> a[i];
sum[i] = sum[i - 1] + a[i];//预处理一下sum值
}
up(i, 0, n+2)
{
up(j, 0, n+2)
{
d[i][j] = inf;
}
}
int sum1 = dp(1, n);
cout << 2 * sum1 - sum[n] << endl;//最后的和表示。
}
return 0;
}