题意:
Alice和Bob玩一个游戏,有两个长度为N的正整数数字序列,每次他们两个只能从其中一个序列,选择两端中的一个拿走。他们都希望可以拿到尽量大的数字之和,并且他们都足够聪明,每次都选择最优策略。Alice先选择,问最终Alice拿到的数字总和是多少?
题解:
区间dp:f[i][j][k][l]表示第1列i到j,第二列k到l情况开始拿,最多可以拿多少,共有四种状态可以选择f[i+1][j][k][l]、f[i][j-1][k][l]、f[i][j][k+1][l]、f[i][j][k][l-1],取最小值即位能拿到的最大值
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n;
int a[22], b[22];
int f[22][22][22][22];
int sum1[22], sum2[22];
int dfs(int a1, int a2, int b1, int b2) {
int& ans = f[a1][a2][b1][b2]; //ans表示达到这个状态需要取的数值,会更新
int now;
if(a1>a2){
now = sum2[b2]-sum2[b1-1];
if(b1==b2)
ans = now;
}else if(b1>b2){
now = sum1[a2]-sum1[a1-1];
if(a1==a2)
ans = now;
}else{
now = sum1[a2]-sum1[a1-1]+sum2[b2]-sum2[b1-1];
}
if(ans!=-1)
return ans;
ans = 0;
if (a1 <= a2) {
ans = max(ans, now - min(dfs(a1+1, a2, b1, b2), dfs(a1, a2-1, b1, b2)));
}
if (b1 <= b2) {
ans = max(ans, now - min(dfs(a1, a2, b1+1, b2), dfs(a1, a2, b1, b2-1)));
}
return ans;
}
int main() {
int nCase;
scanf("%d", &nCase);
while (nCase--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
sum1[i] = sum1[i-1] + a[i];
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &b[i]);
sum2[i] = sum2[i-1] + b[i];
}
memset(f, -1, sizeof(f));
cout << dfs(1, n, 1, n) << endl;
}
return 0;
}