[1563]石子游戏七匹狼系列之五[Tundra Wolf]

在这里插入图片描述

在这里插入图片描述

方法1:记忆化搜索DP

状态定义

dp[l][r] 表示Alice在石子区间[l...r]这个范围内,所能获得的最大的分数

转移方程

Alice从中间的某处,将这两堆石子分开,变成[l...i][i+1...r]时,Bob会拿走其中的一堆:

  • sum[l:i]<sum[i+1:r] 当左部分的和小于右部分的和,Bob会丢弃掉右部分,Alice拿走sum[l:i]dp[l][r]=dp[l][i]+sum[l:i], Alice[l...i]这个区间所能获得的最大分数+这一轮获得的左部分的分数和

  • sum[l:i]>sum[i+1:r],当左部分的和大于右部分的和,Bob会丢弃掉左部分,Alice拿走sum[l+1:r]dp[l][r]=dp[i+1][r]+sum[i+1:r], Alice[i+1...r]这个区间所能获得的最大分数+这一轮获得的左部分的分数和

  • sum[l:i]=sum[i+1:r],当左部分的和等于右部分的和,BobAlice选择左或者右,需要确认左右部分的最大值,即max{dp[l][i],dp[i+1][r]} ,再加上本轮所获取的分数即,sum[l:i] 或者,sum[i+1:r]

  • 要求的是dp[0][n-1]这个值,即在[0...n-1]这个区间范围内,Alice所能获取的最大分数

思路
  • 利用前缀和,来计算区间和

TLE

Map<Pair, Integer> cache = new HashMap<>();
    int[] preSum;


    public int stoneGameV(int[] stoneValue) {
        int n = stoneValue.length;

        preSum = new int[n + 1];
        for (int i = 0; i < n; i++) preSum[i + 1] = preSum[i] + stoneValue[i];
        return dfs(stoneValue, 0, n - 1);
    }

    private int dfs(int[] stoneValue, int i, int j) {
        if (i == j) return 0;
        Pair curr = new Pair(i, j);
        if (cache.get(curr) != null) return cache.get(curr);
        cache.put(curr, 0);
        for (int k = i + 1; k <= j; k++) {
            int l = preSum[k] - preSum[i];
            int r = preSum[j + 1] - preSum[k];
            if (l < r) {
                cache.put(curr, Math.max(cache.get(curr), l + dfs(stoneValue, i, k - 1)));
            } else if (l > r) {
                cache.put(curr, Math.max(cache.get(curr), r + dfs(stoneValue, k, j)));
            } else if (l == r) {
                cache.put(curr, Math.max(cache.get(curr), l + Math.max(dfs(stoneValue, i, k - 1), dfs(stoneValue, k, j))));
            }
        }
        return cache.get(curr);
    }


    class Pair {
        int i;
        int j;

        public Pair(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }

AC

Integer[][] dp;
int[] preSum;


public int stoneGameV(int[] stoneValue) {
    int N = stoneValue.length;
    dp = new Integer[N][N];
    preSum = new int[N + 1];
    for (int i = 0; i < N; i++) preSum[i + 1] = preSum[i] + stoneValue[i];
    return dfs(stoneValue, 0, N - 1);
}

private int dfs(int[] stoneValue, int l, int r) {
    if (l == r) return 0;
    if (dp[l][r] != null) return dp[l][r];
    int ans = 0;
    for (int i = l; i < r; i++) {
        int lValue = preSum[i + 1] - preSum[l];
        int rValue = preSum[r + 1] - preSum[i + 1];
        if (lValue > rValue) {
            ans = Math.max(ans, rValue + dfs(stoneValue, i + 1, r));
        } else if (lValue < rValue) {
            ans = Math.max(ans, lValue + dfs(stoneValue, l, i));
        } else if (lValue == rValue) {
            ans = Math.max(ans, lValue + Math.max(dfs(stoneValue, i + 1, r), dfs(stoneValue, l, i)));
        }
    }
    return dp[l][r] =ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值