题意:
两个玩家A和B在玩一个取石子游戏,且每个石子都有它们各自的价值。在游戏中有这样一个规则:每次取一个石子或者连续几个都必从两端取,要么是最左端,要么是最右端,直到取完为止。两个玩家都非常聪明,他们每次都会去最优的结果。给他们N个石子,你能计算出玩家A,B各自的最后结果吗?假设总是玩家A先开局。
思路:
可以知道整体石子的总和一定的,所以一个人的得分越高,另一个人的得分就越低。不管怎么取任意时刻游戏的状态都是原始序列的一段连续子序列(即被玩家取剩下的序列)。
因此,用d(i,j)表示玩家A在i到j部分的最大和,在双方都采取最优策略的情况下,先手得分最大值。
d[i][j] = sum[i][j] - min(dp(i + k, j), dp(i, j - k)); (1 <= k <= j - i + 1)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int arr[MAXN], d[MAXN][MAXN], sum[MAXN][MAXN];
int n;
void init() {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
d[i][j] = -INF;
for (int i = 0; i < n; i++) {
int num = 0;
for (int j = i; j < n; j++) {
num += arr[j];
sum[i][j] = num;
}
}
}
int dp(int a, int b) {
int &ans = d[a][b];
if (a > b)
return 0;
if (ans != -INF)
return ans;
for (int k = 1; k <= b - a + 1; k++)
ans = max(ans, sum[a][b] - min(dp(a, b - k), dp(a + k, b)));
return ans;
}
int main() {
while (scanf("%d", &n) && n) {
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
init();
int ans = dp(0, n - 1);
printf("%d\n", 2 * ans - sum[0][n - 1]);
}
return 0;
}