石子游戏中,爱丽丝和鲍勃轮流进行自己的回合,爱丽丝先开始 。
有
n
块石子排成一排。每个玩家的回合中,可以从行中 移除 最左边的石头或最右边的石头,并获得与该行中剩余石头值之 和 相等的得分。当没有石头可移除时,得分较高者获胜。鲍勃发现他总是输掉游戏(可怜的鲍勃,他总是输),所以他决定尽力 减小得分的差值 。爱丽丝的目标是最大限度地 扩大得分的差值 。
给你一个整数数组
stones
,其中stones[i]
表示 从左边开始 的第i
个石头的值,如果爱丽丝和鲍勃都 发挥出最佳水平 ,请返回他们 得分的差值 。
class Solution {
public:
int stoneGameVII(vector& stones) {
}
};
1690. 石子游戏 VII
看到1e3数据量想到应该是O(N^2)解法,根据游戏规则不难想到区间dp。
定义f[l][r]为某个玩家先拿手头的情况下,自身得分减去对方得分的最大值。
这样我们会发现,当Alice拿了石头之后,Bob就等效变成了先拿石头的玩家
所以f[l][r] = max(sum(l, r - 1) + dfs(l, r - 1), sum(l + 1, r) + dfs(l + 1, r))
方程还是很好想的,区间dp板子题属于是
时间复杂度:O(N^2) 空间复杂度:O(N^2)
const int N = 1005;
int f[N][N];
class Solution {
public:
int stoneGameVII(vector& s) {
int n = s.size();
for(int i = 1; i < n; i++) s[i] += s[i - 1];
memset(f, -1, sizeof(f));
function pre = [&](int i){
return i >= 0 ? s[i] : 0;
};
function dfs = [&](int l, int r){
if(l >= r) return 0;
if(~f[l][r]) return f[l][r];
int& res = f[l][r] = 0;
res = max(pre(r - 1) - pre(l - 1) - dfs(l, r - 1), pre(r) - pre(l) - dfs(l + 1, r));
return res;
};
return dfs(0, n - 1);
}
};