2023-07-05:爱丽丝和鲍勃继续他们的石子游戏
许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]
游戏以谁手中的石子最多来决出胜负。
爱丽丝和鲍勃轮流进行,爱丽丝先开始。最初,M = 1。
在每个玩家的回合中,该玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M
然后,令 M = max(M, X)。
游戏一直持续到所有石子都被拿走。
假设爱丽丝和鲍勃都发挥出最佳水平W
返回爱丽丝可以得到的最大数量的石头。
输入:piles = [2,7,9,4,4]。
输出:10。
答案2023-07-05:
1.算法 stoneGameII1:暴力方法
函数 second1 的作用是计算鲍勃在当前石子堆的状态下的最优解,其过程与函数 first1 类似。
2.算法 stoneGameII2:记忆化搜索
函数 second2 的作用是计算鲍勃在当前石子堆的状态下的最优解,与函数 second1 类似,但加入了记忆化搜索的机制。
3.算法 stoneGameII3:严格位置依赖的动态规划,一张表的版本
4.算法 stoneGameII4:严格位置依赖的动态规划
stoneGameII1的时间复杂度为O(2^n),空间复杂度为O(n)。
stoneGameII2的时间复杂度为O(n^3),空间复杂度为O(n^2)。
stoneGameII3的时间复杂度为O(n^3),空间复杂度为O(n^2)。
stoneGameII4的时间复杂度为O(n^2),空间复杂度为O(n)。
package main
import (
"fmt"
"math"
)
// 暴力方法
func stoneGameII1(piles []int) int {
return first1(piles, 0, 1)
}
func first1(piles []int, index, m int) int {
if index == len(piles) {
return 0
}
best := 0
pre := 0
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
pre += piles[i]
best = int(math.Max(float64(best), float64(pre+second1(piles, i+1, int(math.Max(float64(j), float64(m)))))))
}
return best
}
func second1(piles []int, index, m int) int {
if index == len(piles) {
return 0
}
worse := math.MaxInt64
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
worse = int(math.Min(float64(worse), float64(first1(piles, i+1, int(math.Max(float64(j), float64(m)))))))
}
return worse
}
// 记忆化搜索
func stoneGameII2(piles []int) int {
n := len(piles)
f := make([][]int, n)
s := make([][]int, n)
for i := 0; i < n; i++ {
f[i] = make([]int, n+1)
s[i] = make([]int, n+1)
for j := 0; j <= n; j++ {
f[i][j] = -1
s[i][j] = -1
}
}
return first2(piles, 0, 1, f, s)
}
func first2(piles []int, index, m int, f, s [][]int) int {
if index == len(piles) {
return 0
}
if f[index][m] != -1 {
return f[index][m]
}
best := 0
pre := 0
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
pre += piles[i]
best = int(math.Max(float64(best), float64(pre+second2(piles, i+1, int(math.Min(float64(len(piles)), float64(math.Max(float64(j), float64(m))))), f, s))))
}
f[index][m] = best
return best
}
func second2(piles []int, index, m int, f, s [][]int) int {
if index == len(piles) {
return 0
}
if s[index][m] != -1 {
return s[index][m]
}
worse := math.MaxInt64
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
worse = int(math.Min(float64(worse), float64(first2(piles, i+1, int(math.Min(float64(len(piles)), float64(math.Max(float64(j), float64(m))))), f, s))))
}
s[index][m] = worse
return worse
}
// 严格位置依赖的动态规划,一张表的版本
func stoneGameII3(piles []int) int {
n := len(piles)
f := make([][]int, n+1)
s := make([][]int, n+1)
for i := 0; i <= n; i++ {
f[i] = make([]int, n+1)
s[i] = make([]int, n+1)
}
sum := 0
for index := n - 1; index >= 0; index-- {
sum += piles[index]
for m := 1; m <= n; m++ {
best := 0
pre := 0
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
pre += piles[i]
best = int(math.Max(float64(best), float64(pre+s[i+1][int(math.Min(float64(n), float64(math.Max(float64(j), float64(m)))))])))
}
f[index][m] = best
worse := math.MaxInt64
for i, j := index, 1; i < len(piles) && j <= 2*m; i, j = i+1, j+1 {
worse = int(math.Min(float64(worse), float64(f[i+1][int(math.Min(float64(n), float64(math.Max(float64(j), float64(m)))))])))
}
s[index][m] = worse
}
}
return f[0][1]
}
// 严格位置依赖的动态规划
func stoneGameII4(piles []int) int {
n := len(piles)
sum := 0
dp := make([][]int, n)
for i := range dp {
dp[i] = make([]int, n+1)
}
for i := n - 1; i >= 0; i-- {
sum += piles[i]
for m := 1; m <= n; m++ {
if i+2*m >= n {
dp[i][m] = sum
} else {
nextMin := math.MaxInt64
for x := 1; x <= 2*m; x++ {
nextMin = int(math.Min(float64(nextMin), float64(dp[i+x][int(math.Max(float64(m), float64(x)))])))
}
dp[i][m] = sum - nextMin
}
}
}
return dp[0][1]
}
func main() {
piles := []int{2, 7, 9, 4, 4}
fmt.Println("stoneGameII1:", stoneGameII1(piles))
fmt.Println("stoneGameII2:", stoneGameII2(piles))
fmt.Println("stoneGameII3:", stoneGameII3(piles))
fmt.Println("stoneGameII4:", stoneGameII4(piles))
}
在这里插入图片描述
fn stone_game_ii1(piles: Vec<i32>) -> i32 {
first1(&piles, 0, 1)
}
fn first1(piles: &Vec<i32>, index: usize, m: i32) -> i32 {
if index == piles.len() {
return 0;
}
let mut best = 0;
let mut pre = 0;
for i in index..piles.len().min(index + (2 * m) as usize) {
pre += piles[i];
best = best.max(pre + second1(piles, i + 1, m.max(i as i32 + 1)));
}
best
}
fn second1(piles: &Vec<i32>, index: usize, m: i32) -> i32 {
if index == piles.len() {
return 0;
}
let mut worse = i32::MAX;
for i in index..piles.len().min(index + (2 * m) as usize) {
worse = worse.min(first1(piles, i + 1, m.max(i as i32 + 1)));
}
worse
}
fn stone_game_ii2(piles: Vec<i32>) -> i32 {
let mut f = vec![vec![-1; piles.len() + 1]; piles.len()];
let mut s = vec![vec![-1; piles.len() + 1]; piles.len()];
first2(&piles, 0, 1, &mut f, &mut s)
}
fn first2(
piles: &Vec<i32>,
index: usize,
m: usize,
f: &mut Vec<Vec<i32>>,
s: &mut Vec<Vec<i32>>,
) -> i32 {
if index == piles.len() {
return 0;
}
if f[index][m] != -1 {
return f[index][m];
}
let mut best = 0;
let mut pre = 0;
for i in index..piles.len().min(index + 2 * m) {
pre += piles[i];
best = best.max(pre + second2(piles, i + 1, m.max(i - index + 1), f, s));
}
f[index][m] = best;
best
}
fn second2(
piles: &Vec<i32>,
index: usize,
m: usize,
f: &mut Vec<Vec<i32>>,
s: &mut Vec<Vec<i32>>,
) -> i32 {
if index == piles.len() {
return 0;
}
if s[index][m] != -1 {
return s[index][m];
}
let mut worse = i32::MAX;
for i in index..piles.len().min(index + 2 * m) {
worse = worse.min(first2(piles, i + 1, m.max(i - index + 1), f, s));
}
s[index][m] = worse;
worse
}
fn stone_game_ii3(piles: Vec<i32>) -> i32 {
let n = piles.len();
let mut f: Vec<Vec<i32>> = vec![vec![0; n + 1]; n + 1];
let mut s: Vec<Vec<i32>> = vec![vec![0; n + 1]; n + 1];
for index in (0..n).rev() {
for m in 1..=n {
let mut pre = 0;
for (i, j) in (index..piles.len()).zip(1..=2 * m) {
pre += piles[i];
f[index][m] = f[index][m].max(pre + s[i + 1][n.min(j.max(m))]);
}
s[index][m] = i32::MAX;
for (i, j) in (index..piles.len()).zip(1..=2 * m) {
s[index][m] = s[index][m].min(f[i + 1][n.min(j.max(m))]);
}
}
}
f[0][1]
}
fn stone_game_ii4(piles: Vec<i32>) -> i32 {
let n = piles.len();
let mut sum = 0;
let mut dp = vec![vec![0; n + 1]; n];
for i in (0..n).rev() {
sum += piles[i];
for m in 1..=n {
if i + 2 * m >= n {
dp[i][m] = sum;
} else {
let mut next_min = std::i32::MAX;
for x in 1..=2 * m {
next_min = next_min.min(dp[i + x][m.max(x)]);
}
dp[i][m] = sum - next_min;
}
}
}
dp[0][1]
}
fn main() {
let piles = vec![2, 7, 9, 4, 4];
let result = stone_game_ii1(piles);
println!("{}", result);
let piles = vec![2, 7, 9, 4, 4];
let result = stone_game_ii2(piles);
println!("{}", result);
let piles = vec![2, 7, 9, 4, 4];
let result = stone_game_ii3(piles);
println!("{}", result);
let piles = vec![2, 7, 9, 4, 4];
let result = stone_game_ii4(piles);
println!("{}", result);
}
在这里插入图片描述
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
int second1(vector<int>& piles, int index, int m);
int first1(vector<int>& piles, int index, int m) {
if (index == piles.size()) {
return 0;
}
int best = 0;
int pre = 0;
for (int i = index, j = 1; i < piles.size() && j <= 2 * m; i++, j++) {
pre += piles[i];
best = max(best, pre + second1(piles, i + 1, max(j, m)));
}
return best;
}
int second1(vector<int>& piles, int index, int m) {
if (index == piles.size()) {
return 0;
}
int worse = INT_MAX;
for (int i = index, j = 1; i < piles.size() && j <= 2 * m; i++, j++) {
worse = min(worse, first1(piles, i + 1, max(j, m)));
}
return worse;
}
int stoneGameII1(vector<int>& piles) {
return first1(piles, 0, 1);
}
int second2(vector<int>& piles, int index, int m, vector<vector<int>>& f, vector<vector<int>>& s);
int first2(vector<int>& piles, int index, int m, vector<vector<int>>& f, vector<vector<int>>& s) {
if (index == piles.size()) {
return 0;
}
if (f[index][m] != -1) {
return f[index][m];
}
int best = 0;
int pre = 0;
for (int i = index, j = 1; i < piles.size() && j <= 2 * m; i++, j++) {
pre += piles[i];
best = max(best, pre + second2(piles, i + 1, min((int)piles.size(), max(j, m)), f, s));
}
f[index][m] = best;
return best;
}
int second2(vector<int>& piles, int index, int m, vector<vector<int>>& f, vector<vector<int>>& s) {
if (index == piles.size()) {
return 0;
}
if (s[index][m] != -1) {
return s[index][m];
}
int worse = INT_MAX;
for (int i = index, j = 1; i < piles.size() && j <= 2 * m; i++, j++) {
worse = min(worse, first2(piles, i + 1, min((int)piles.size(), max(j, m)), f, s));
}
s[index][m] = worse;
return worse;
}
int stoneGameII2(vector<int>& piles) {
int n = piles.size();
vector<vector<int>> f(n, vector<int>(n + 1, -1));
vector<vector<int>> s(n, vector<int>(n + 1, -1));
return first2(piles, 0, 1, f, s);
}
int stoneGameII3(vector<int>& piles) {
int n = piles.size();
vector<vector<int>> f(n + 1, vector<int>(n + 1, 0));
vector<vector<int>> s(n + 1, vector<int>(n + 1, 0));
for (int index = n - 1; index >= 0; index--) {
for (int m = 1; m <= n; m++) {
int pre = 0;
for (int i = index, j = 1; i < n && j <= 2 * m; i++, j++) {
pre += piles[i];
f[index][m] = max(f[index][m], pre + s[i + 1][min(n, max(j, m))]);
}
s[index][m] = INT_MAX;
for (int i = index, j = 1; i < n && j <= 2 * m; i++, j++) {
s[index][m] = min(s[index][m], f[i + 1][min(n, max(j, m))]);
}
}
}
return f[0][1];
}
int stoneGameII4(vector<int>& piles) {
int n = piles.size();
int sum = 0;
vector<vector<int>> dp(n, vector<int>(n + 1, 0));
for (int i = n - 1; i >= 0; i--) {
sum += piles[i];
for (int m = 1; m <= n; m++) {
if (i + 2 * m >= n) {
dp[i][m] = sum;
}
else {
int nextMin = INT_MAX;
for (int x = 1; x <= 2 * m; x++) {
nextMin = min(nextMin, dp[i + x][max(m, x)]);
}
dp[i][m] = sum - nextMin;
}
}
}
return dp[0][1];
}
int main() {
vector<int> piles = { 2, 7, 9, 4, 4 };
cout << "stoneGameII1: " << stoneGameII1(piles) << endl;
cout << "stoneGameII2: " << stoneGameII2(piles) << endl;
cout << "stoneGameII3: " << stoneGameII3(piles) << endl;
cout << "stoneGameII4: " << stoneGameII4(piles) << endl;
return 0;
}
在这里插入图片描述
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int second1(int* piles, int pilesSize, int index, int m);
int first1(int* piles, int pilesSize, int index, int m) {
if (index == pilesSize) {
return 0;
}
int best = 0;
int pre = 0;
for (int i = index, j = 1; i < pilesSize && j <= 2 * m; i++, j++) {
pre += piles[i];
best = best > (pre + second1(piles, pilesSize, i + 1, j > m ? j : m)) ? best : (pre + second1(piles, pilesSize, i + 1, j > m ? j : m));
}
return best;
}
int second1(int* piles, int pilesSize, int index, int m) {
if (index == pilesSize) {
return 0;
}
int worse = INT_MAX;
for (int i = index, j = 1; i < pilesSize && j <= 2 * m; i++, j++) {
worse = worse < first1(piles, pilesSize, i + 1, j > m ? j : m) ? worse : first1(piles, pilesSize, i + 1, j > m ? j : m);
}
return worse;
}
int stoneGameII1(int* piles, int pilesSize) {
return first1(piles, pilesSize, 0, 1);
}
int second2(int* piles, int pilesSize, int index, int m, int** f, int** s);
int first2(int* piles, int pilesSize, int index, int m, int** f, int** s) {
if (index == pilesSize) {
return 0;
}
if (f[index][m] != -1) {
return f[index][m];
}
int best = 0;
int pre = 0;
for (int i = index, j = 1; i < pilesSize && j <= 2 * m; i++, j++) {
pre += piles[i];
best = best > (pre + second2(piles, pilesSize, i + 1, j > m ? j : m, f, s)) ? best : (pre + second2(piles, pilesSize, i + 1, j > m ? j : m, f, s));
}
f[index][m] = best;
return best;
}
int second2(int* piles, int pilesSize, int index, int m, int** f, int** s) {
if (index == pilesSize) {
return 0;
}
if (s[index][m] != -1) {
return s[index][m];
}
int worse = INT_MAX;
for (int i = index, j = 1; i < pilesSize && j <= 2 * m; i++, j++) {
worse = worse < first2(piles, pilesSize, i + 1, j > m ? j : m, f, s) ? worse : first2(piles, pilesSize, i + 1, j > m ? j : m, f, s);
}
s[index][m] = worse;
return worse;
}
int stoneGameII2(int* piles, int pilesSize) {
int n = pilesSize;
int** f = (int**)malloc((n + 1) * sizeof(int*));
int** s = (int**)malloc((n + 1) * sizeof(int*));
for (int i = 0; i < n; i++) {
f[i] = (int*)malloc((n + 1) * sizeof(int));
s[i] = (int*)malloc((n + 1) * sizeof(int));
for (int j = 0; j <= n; j++) {
f[i][j] = -1;
s[i][j] = -1;
}
}
return first2(piles, pilesSize, 0, 1, f, s);
}
int stoneGameII3(int* piles, int pilesSize) {
int n = pilesSize;
int** f = (int**)malloc((n + 1) * sizeof(int*));
int** s = (int**)malloc((n + 1) * sizeof(int*));
for (int i = 0; i <= n; i++) {
f[i] = (int*)malloc((n + 1) * sizeof(int));
s[i] = (int*)malloc((n + 1) * sizeof(int));
for (int j = 0; j <= n; j++) {
f[i][j] = 0;
s[i][j] = 0;
}
}
for (int index = n - 1; index >= 0; index--) {
for (int m = 1; m <= n; m++) {
int pre = 0;
for (int i = index, j = 1; i < n && j <= 2 * m; i++, j++) {
pre += piles[i];
f[index][m] = f[index][m] > (pre + s[i + 1][j > m ? j : m]) ? f[index][m] : (pre + s[i + 1][j > m ? j : m]);
}
s[index][m] = INT_MAX;
for (int i = index, j = 1; i < n && j <= 2 * m; i++, j++) {
s[index][m] = s[index][m] < f[i + 1][j > m ? j : m] ? s[index][m] : f[i + 1][j > m ? j : m];
}
}
}
return f[0][1];
}
int stoneGameII4(int* piles, int pilesSize) {
int n = pilesSize;
int sum = 0;
int** dp = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
dp[i] = (int*)malloc((n + 1) * sizeof(int));
for (int j = 0; j <= n; j++) {
dp[i][j] = 0;
}
}
for (int i = n - 1; i >= 0; i--) {
sum += piles[i];
for (int m = 1; m <= n; m++) {
if (i + 2 * m >= n) {
dp[i][m] = sum;
}
else {
int nextMin = INT_MAX;
for (int x = 1; x <= 2 * m; x++) {
nextMin = nextMin < dp[i + x][m > x ? m : x] ? nextMin : dp[i + x][m > x ? m : x];
}
dp[i][m] = sum - nextMin;
}
}
}
return dp[0][1];
}
int main() {
int piles[] = { 2, 7, 9, 4, 4 };
int pilesSize = sizeof(piles) / sizeof(piles[0]);
printf("stoneGameII1: %d\n", stoneGameII1(piles, pilesSize));
printf("stoneGameII2: %d\n", stoneGameII2(piles, pilesSize));
printf("stoneGameII3: %d\n", stoneGameII3(piles, pilesSize));
printf("stoneGameII4: %d\n", stoneGameII4(piles, pilesSize));
return 0;
}
在这里插入图片描述