leetcode https://leetcode.com/problems/stone-game-ii/
是stone game的进阶
递归
public int stoneGameII(int[] piles) {
int len=piles.length;
if(len<1)return 0;
if(len<2)return piles[0];
int dp[][]=new int[len][len*2];
int sum[]=new int[len];
for(int i=len-1;i>=0;i--){
sum[i]+=(i+1<len?sum[i+1]:0)+piles[i];//代表从i到末尾的数值的和
}
return helper(piles,0,1,dp,sum);
}
int helper(int piles[],int idx,int M,int [][]dp,int []sum){
if(idx==piles.length){
return 0;
}
if(piles.length-idx<=2*M)return sum[idx];
if(dp[idx][M]!=0){
return dp[idx][M];
}
int min=Integer.MAX_VALUE;
for(int i=1;i<=2*M;i++) {
min = Math.min(min, helper(piles, idx + i, Math.max(M, i), dp, sum));
}
dp[idx][M]=sum[idx]-min;//sum[i]代表第一个人能拿到的最多的石头,min代表的是第二个人拿到最少的石头,所以减一下得到实际能拿到多少
return dp[idx][M];
}
动态规划
public:
int stoneGameII(vector<int>& piles) {
int len = piles.size();
vector<vector<int>> dp(len, vector<int>(len, 0));
vector<int> sum(len, 0);
// 逆序部分和
sum.back() = piles.back();
for(int i=len-2; i>=0; i--) sum[i] = sum[i+1] + piles[i];
// 倒着查找 dp[i][j] 代表当前在 i 位置,且此时 M = j-1 可以获得的最大收益
for(int i=len-1; i>=0; i--)
// 把可能情况都探索一遍,其中 M 的可能大小为 1 到 len
for(int j=0; j<len; j++){
// 剩下的点可以一次拿完
int M = j+1;
if(2*M >= len-i) dp[i][j] = sum[i];
else{
// 一次拿不完的情况,取最大值
for(int k=1; k<=2*M; k++)
dp[i][j] = max(dp[i][j], sum[i]-dp[i+k][max(k, M)-1]);
}
}
return dp[0][0];
}