The DFS solution is quite intuitive and more like an implementation.
Try to think in this way, every time you can either choose X piles, and this X would affect the latter decisions. And as both Alice and Bobs would make decisions optimally. We need to relate these two variables. The difference between the stones of Alice and Bob gotten is the best way to relate them. That's because if we maximize the difference between Alice and Bob, it is the same to help them maximize the stones.
However, the answer required to return Alice's stones. Let's say Alice's stones are a and Bob's stones are b, the difference is a - b and the total stone of the piles is a + b, total - difference = 2a, thus if we want to get the number of Alice's stones. Just need to use the sum of piles of stone to deduct the difference and then divide it by 2.
What are the base cases?
If 2 * m is larger than the rest length of the piles, the optimal choice is to take all of them.
For pruning, we would use a memorization array to store the value of different choices, if there are repeating cases, just return the answer.
class Solution {
public:
int dfs(vector<int>& piles, int len, int m, vector<vector<int>> &dp){
if(len >= piles.size())return 0;
m = min(int(piles.size()), m);
if(dp[len][m] > 0)return dp[len][m];
if(piles.size() <= len + m * 2)return dp[len][m] = accumulate(piles.begin() + len, piles.end(), 0);
int count = 0;
int best = INT_MIN;
for(int i = 1; i <= 2 * m; i++){
count += piles[len + i - 1];
int n = dfs(piles, len + i, max(i, m), dp);
best = max(best, count - n);
}
return dp[len][m] = best;
}
int stoneGameII(vector<int>& piles) {
vector<vector<int>> dp(102, vector<int>(102));
int part = dfs(piles, 0, 1, dp);
return (accumulate(piles.begin(), piles.end(), 0) + part)/2;
}
};
For the Dp solution, it is quite hard to think of. We need to think backwardly. In DFS, we try to use recursion to get the base case answer and then accumulate it backwardly.
As DP is iterative, we need to do our DP reversely.
Dp[i][j] is the maximum stone that a player can get starting with index i and with j's taken.
So the equation of the DP would be to total stones deduct opponents value. dp[i][j] = max(total stone form piles i to n - dp[i + x][x]))
so it would be an O(n^2 M) solution.
O(n) for iterating the piles from the back to front,
O(n) for setting different M,
O(M) for search for the best M.
class Solution {
public:
int stoneGameII(vector<int>& piles) {
vector<vector<int>> dp(102, vector<int>(102));
int n = piles.size();
int suffix[102] = {0};
for(int i = n - 1; i >= 0; i--){
suffix[i] = suffix[i + 1] + piles[i];
}
for (int i = 0; i <= n; i++) {
dp[i][n] = suffix[i];
}
for(int i = n - 1; i >= 0; i--){
for(int j = 1; j <= n - 1; j++){
for(int x = 1; x <= 2 * j && i + x <= n; x++){
dp[i][j] = max(dp[i][j], suffix[i] - dp[i + x][max(j, x)]);
}
}
}
return dp[0][1];
}
};