石子游戏——记忆化搜索

60 阅读1分钟

image.png

代码:

本题很明显要用记忆化搜索或者动态规划来求解,如果直接使用动态规划的话,我们要想清楚有哪些子状态需要存储。

首先一定要存储的是取到某一个位置时,已经得到的最大值或者后面能得到的最大值,但是光有位置是不够的,相同的位置有不同数量的堆可以取,所以我们还需存储当前的M值。

由于本题中的状态是从后往前递推的,如:假如最后只剩一堆,一定能算出来最佳方案,但是剩很多堆时不好算(依赖后面的状态)。所以我们选择从后往前递推。

func stoneGameII(piles []int) int {
    prefixSum := make([]int, len(piles)+1)
    for i, v := range piles {
        prefixSum[i+1] = prefixSum[i] + v
    }
    type pair struct{ i, m int }
    dp := map[pair]int{}
    var f func(int, int) int
    f = func(i int, m int) int {
        if i == len(piles) {
            return 0
        }
        if v, ok := dp[pair{i, m}]; ok {
            return v
        }
        maxVal := math.MinInt
        for x := 1; x <= 2*m; x++ {
            if i+x > len(piles) {
                break
            }
            maxVal = max(maxVal, prefixSum[i+x]-prefixSum[i]-f(i+x, max(m, x)))
        }
        dp[pair{i, m}] = maxVal
        return maxVal
    }
    return (prefixSum[len(piles)] + f(0, 1)) / 2
}

func max(a, b int) int {
    if b > a {
        return b
    }
    return a
}