HDU-4597 Play Game(Game + Interval dp)

アリスとボブはゲームをしています。カードの山は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つの配列の最初または最後の数字しか取れないので、アリスに数字の最大合計を取るように依頼します。

アイデア:dp [i] [j] [p] [q] 最初の配列が残り [i、j] 、2番目の配列が残っ [P、q] ている場合、次のステップを実行する人が取得できる最大値は、前のステップの相手の最大値から転送できます。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;
}

 

おすすめ

転載: blog.csdn.net/weixin_43871207/article/details/109783072