- DP
这里记录一下思考DP的过程。
石子堆的个数只会两个两个地增加,这自然可以作为我们DP的阶段划分。
用 来分别表示序列 ~ 的石子堆,爱丽丝先手取第一个石子堆和最后一个石子堆能都获得的最大值。
我们以 为例分析,也就是分析[l~r]的序列,爱丽丝先手取第一个石子堆能够获得的最大值。
既然爱丽丝取了a[l],那么李就要么取a[l+1],要么取a[r],而这分别对应上图第③、第②种情况的依赖,取完之后,就是分析相同类似情况的子结构了。
但要注意李要保证自己的决策最优,就要是依赖的子结构Alice可以获得的式子尽可能地少。
那么DP就是:
类似的
也可以写出。
当然很明显,我们可以直接用
表示序列l~r爱丽丝能够获得的最大值,这样代码更清晰。
class Solution {
public:
bool stoneGame(vector<int>& a) {
int n = a.size(), sum = 0;
for(int x:a){
sum += x;
}
vector<vector<int>> dp(n,vector<int>(n));
for(int l=0;l+1<n;l++){
dp[l][l+1] = max(a[l],a[l+1]);
}
for(int k = 4;k<=n;k+=2){
for(int l=0;l+k-1<n;l++){
int r = l+k-1;
int s1 = a[l]+min(dp[l+2][r],dp[l+1][r-1]);
int s2 = a[r]+min(dp[l][r-2],dp[l+1][r-1]);
dp[l][r] = max(s1,s2);
}
}
return max(dp[0][n-1],dp[0][n-1])>sum/2;
}
};
- 数学思维
可以用归纳的方式证明,先手的人必赢(这个和堆数为偶数有相当的关系)
于是直接返回true就可以了。
这里也就不证了,很容易想通,但不容易直接想到,而且对以后的做题帮助也不大。