hdu4597 PlayGame(区间dp)

题意:

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 
#include 
#include 
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;
}

你可能感兴趣的:(算法,dp)