Leetcode 1140. Stone Game II

题目链接:1140. Stone Game II

看到 Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get. 这句话以为是博弈论的题,没想到是一道DP。
首先定义状态 dp[i][M] 表示从piles[i]开始拿(也就是说当前剩下的piles为 i , i + 1 , … , n i,i+1,\dots,n i,i+1,,n ),且 1 ≤ X ≤ 2 M 1\leq X \leq 2M 1X2M 时(X为可以拿走的堆数),当前玩家能够获得的最大的石块数。根据上述定义,答案就是 dp[0][1]

那么如何保证两个人都是最优决策呢?这里实际上枚举了两个人所有的情况,然后得到最优决策。如果直接深度优先搜索的话,应该会TLE,这里使用dp数组来记忆计算过的状态,避免了重复计算,大大减少了时间。

状态转移方程如下:

for (int x = 1;x <= 2*M;++x){
	mini = min(mini, helper(piles, i+x, max(M, x))); 
}
dp[i][M] = sum[i] - mini;

helper(piles, i, M)用来计算dp[i][M],for循环枚举了当前玩家的所有取法,然后计算下一个玩家在当前取法下能够得到的最大石块数,然后我们最大中取最小,得到了dp[i][M]。

C++代码如下:

class Solution {
private:
	vector<int> sum;
	vector<vector<int>> dp;
public:
    int stoneGameII(vector<int>& piles) {
    	int n = piles.size();

    	if (n == 0) return 0;
    	
    	sum =  vector<int>(n, 0);

    	sum[n-1] = piles[n-1];
    	for (int i = n-2;i >= 0;--i){
    		sum[i] = sum[i+1] + piles[i];
    	}

    	dp =  vector<vector<int>> (n, vector<int>(n, 0));

    	return helper(piles, 0, 1);
        
    }

    int helper(vector<int>& piles, int i, int M){
    	if (i >= piles.size()) return 0;
    	if (2*M >= piles.size()-i) return sum[i];
    	if (dp[i][M] != 0) return dp[i][M];

    	int mini = INT_MAX;
    	for (int x = 1;x <= 2*M;++x){
    		mini = min(mini, helper(piles, i+x, max(M, x))); 
    	}
    	dp[i][M] = sum[i] - mini;
    	return dp[i][M];
    }
};

参考:
[Java] DP with memorization, easy to understand(with explanation)

你可能感兴趣的:(leetcode)