区间DP
石子游戏(每次只能选择 前端或者后端的那一堆)的主要思想是 计算当前局面先手的人选择的那一堆 和 他留给另一个人的局面 从中选出最优解
f[i] [j]考虑区间 [l, r]之间双方都做最优选择 先手后手的最大分差是多少
dfs(i, j) 双指针表示当前可以取的前端和后端 然后每次取的时候 的好处为 当前先手取得的值减去留给对手的局面所能获得的值
取i和取j两种选择 选较大的
注意当i==j的时候为退出条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Solution { public: bool stoneGame(vector<int>& piles) {
int n = piles.size(); vector<vector<int>>dp(n, vector<int>(n, 0)); 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; } };
|
这个和上一个有不同的地方 这个题每次是把剩余的全部加起来 所以dfs的时候要先计算出sum (注意每次加之前要先减去当前取的值)相当于dfs多出来一个变量sum
而动态规划写法不能这样 就只能先计算出区间和 每次加上区间和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| class Solution { public: int stoneGameVII(vector<int>& nums) {
int n = nums.size(); vector<vector<int>>sum(n, vector<int>(n, 0)); vector<vector<int>>dp(n, vector<int>(n, 0)); for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { if (i == j)sum[i][j] = nums[i]; else sum[i][j] = sum[i][j - 1] + nums[j]; } }
for (int i = n - 2; i >= 0; i--) { for (int j = i + 1; j < n; j++) { dp[i][j] = max(sum[i + 1][j] - dp[i + 1][j], sum[i][j - 1] - dp[i][j - 1]); } } return dp[0][n - 1]; } };
|