题目链接:Leetcode877

思路:
dp[i][j]表示从下标i到j中去左边和取右边的最大值
转移方程:dp[i][j]=max(dp[i+1][j]+val[i], dp[i][j-1]+val[j]);
显然,根据这个状态的设定有dp[i][i]=val[i];除此之外,i<=j
记忆化搜索:
class Solution {
public:
bool stoneGame(vector<int>& piles) {
int d[500][500]={0};
return dp(0, piles.size()-1, d, piles)>0;
}
int dp(unsigned int l, unsigned int r, int d[][500], vector<int>& piles) {
if(d[l][r]) return d[l][r];
if(l==r) return d[l][r]=piles[l];
return d[l][r]=max(piles[l]+dp(l+1, r, d, piles), piles[r]+dp(l, r-1, d, piles));
}
};
修正:虽然上面能AC,但似乎不符我的原意:
class Solution {
public:
bool stoneGame(vector<int>& piles) {
int d[500][500]={0};
int sum=0;
for(int i=0; i<piles.size(); i++) sum+=piles[i];
return 2*dp(0, piles.size()-1, d, piles)>sum;
}
int dp(unsigned int l, unsigned int r, int d[][500], vector<int>& piles) {
if(r-l==1) return d[l][r]=max(piles[l], piles[r]);
if(d[l][r]) return d[l][r];
return d[l][r]=max(piles[l]+min(dp(l+2, r, d, piles), dp(l+1, r-1, d, piles)), piles[r]+min(dp(l+1, r-1, d, piles), dp(l, r-2, d, piles))); //一次博弈后剩余的最少
}
};
迭代:
class Solution {
public:
bool stoneGame(vector<int>& piles) {
//关于递推的顺序由于要满足子问题先解决,所以要让区间长度由小到大递推
//所以i和j的方向要相反
int dp[500][500], n=piles.size();
for(int i=0; i<n; i++) dp[i][i]=piles[i];
for(int i=n-2; i>=0; i--)
for(int j=i+1; j<n; j++)
dp[i][j]=max(piles[i]+dp[i+1][j], piles[j]+dp[i][j-1]);
return dp[0][n-1]>0;
}
};
规律:
发现这个设置的状态无论如何都会满足最大值大于0,所以这个问题先手必胜,返回一个true也能解决问题
LeetCode 877石头游戏DP解法

本文详细解析了LeetCode题目877石头游戏的动态规划解法,包括状态定义、转移方程及记忆化搜索、迭代实现方式。通过分析,无论状态如何设定,先手玩家总能取得优势,确保胜利。
2303

被折叠的 条评论
为什么被折叠?



