アリスとボブはゲームをしています。カードの山は2つあります。各山にはN枚のカードがあり、各カードにはスコアがあります。彼らは交代でどちらかの山から一番上のカードか一番下のカードを拾い上げ、カードのスコアが彼の合計スコアに追加されます。アリスとボブはどちらも十分に賢く、できるだけ多くのスコアを取得するためにカードを拾います。アリスが最初に拾った場合、いくつのスコアを取得できるか知っていますか?
入力
最初の行には、ケースの数を示す整数T(T≤100)が含まれています。
各ケースには3行が含まれています。最初の行はN(N≤20)です。2行目には、N個の整数ai(1≤ai≤10000)が含まれています。3行目には、N個の整数bi(1≤bi≤10000)が含まれています。
出力
いずれの場合も、アリスが取得できる最大のスコアを示す整数を出力します。
サンプル入力
2 1 23 53 3 10100 20 2 4 3
サンプル出力
53 105
質問の意味:アリスとボブは交代で2つの配列の数字を取ります。そのたびに、1つの配列の最初または最後の数字しか取れないので、アリスに数字の最大合計を取るように依頼します。
アイデア: 最初の配列が残り 、2番目の配列が残っ ている場合、次のステップを実行する人が取得できる最大値は、前のステップの相手の最大値から転送できます。4つの転送方法:配列の最初、配列1の最後、配列2の最初、配列2の最後。
forループを記述したり、検索をメモしたりするのは非常に困難です8
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 25;
int a[N], b[N], dp[N][N][N][N], n;
int dfs(int i, int j, int p, int q, int sum) {
if(i > j && p > q) return 0;
if(dp[i][j][p][q]) return dp[i][j][p][q];
if(i <= j) {
dp[i][j][p][q] = max(dp[i][j][p][q], sum - dfs(i + 1, j, p, q, sum - a[i]));
dp[i][j][p][q] = max(dp[i][j][p][q], sum - dfs(i, j - 1, p, q, sum - a[j]));
}
if(p <= q) {
dp[i][j][p][q] = max(dp[i][j][p][q], sum - dfs(i, j, p + 1, q, sum - b[p]));
dp[i][j][p][q] = max(dp[i][j][p][q], sum - dfs(i, j, p, q - 1, sum - b[q]));
}
return dp[i][j][p][q];
}
int main(){
// freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
int sum = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
sum += a[i];
}
for(int i = 1; i <= n; ++i) {
scanf("%d", &b[i]);
sum += b[i];
}
memset(dp, 0, sizeof(dp));
printf("%d\n", dfs(1, n, 1, n, sum));
}
return 0;
}