问题描述

1140. 石子游戏 II (Medium)

爱丽丝和鲍勃继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子

piles[i]。游戏以谁手中的石子最多来决出胜负。

爱丽丝和鲍勃轮流进行,爱丽丝先开始。最初, M = 1

在每个玩家的回合中,该玩家可以拿走剩下的 X 堆的所有石子,其中 1 <= X <= 2M。然后,令

M = max(M, X)

游戏一直持续到所有石子都被拿走。

假设爱丽丝和鲍勃都发挥出最佳水平,返回爱丽丝可以得到的最大数量的石头。

示例 1:

输入:piles = [2,7,9,4,4]
输出:10
解释:如果一开始Alice取了一堆,Bob取了两堆,然后Alice再取两堆。爱丽丝可以得到2 + 4 + 4 =
10堆。如果Alice一开始拿走了两堆,那么Bob可以拿走剩下的三堆。在这种情况下,Alice得到2 + 7 =
9堆。返回10,因为它更大。

示例 2:

输入:piles = [1,2,3,4,5,100]
输出:104

提示:

  • 1 <= piles.length <= 100
  • 1 <= piles[i] <= 10⁴

解题思路

首先这里要明确发挥最佳水平的含义:

如果自己拿了前x块石子之后,对方所能拿到的石子最少,这就是博弈中的发挥最佳水平,对应到dfs,明白了这一点就能写出递归和记忆化搜索,注意这里还需要用到后缀数组。

写出记忆化搜索之后可以改写成动态规划。

代码

记忆化搜索

class Solution {
public:
int dfs(int idx_start, int M, vector<int> &postfix, int n, vector<vector<int>> &cach) {
if (idx_start >= n)
return 0; int minnum = 100001;
if (cach[idx_start][M] >= 0) {
return cach[idx_start][M];
}
for (int i = idx_start + 1; i <= idx_start + 2 * M && i <= n; i++) { // i表示下一个人拿石子的开始位置,所以i至少为idx_start+1
int tmp = dfs(i, std::max(i - idx_start, M), postfix, n, cach);
if (minnum > tmp) {
minnum = tmp;
}
}
cach[idx_start][M] = postfix[idx_start] - minnum;
return cach[idx_start][M]; }
int stoneGameII(vector<int>& piles) {
int n = piles.size();
vector<int> postfix(n + 1, 0);
for (int i = n - 1; i >= 0; i--) {
postfix[i] = postfix[i + 1] + piles[i];
}
vector<vector<int>> cach(n + 1, vector<int>(n, -1));
return dfs(0, 1, postfix, n, cach);
}
};

动态规划

class Solution {
public:
int stoneGameII(vector<int> &piles) {
int n = piles.size();
vector<int> postfix(n + 1, 0);
// 后缀和数组
for (int i = n - 1; i >= 0; i--) {
postfix[i] = postfix[i + 1] + piles[i];
}
// dp[i][j]表示从坐标`i`开始拿`j`个所能获得的最大石子数
vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));
for (int i = n - 1; i >= 0; i--) {
for (int M = 1; M <= i / 2 + 1; M++) {
if (i + 2 * M >= n) { // 说明可以直接拿走剩余的石子
dp[i][M] = postfix[i];
} else {
int min_num = INT_MAX;
for (int x = 1; x <= 2 * M; x++) {
// 因为从dp[i + x]递推到dp[i],所以`i`要倒序循环
min_num = std::min(min_num, dp[i + x][std::max(M, x)]);
}
dp[i][M] = postfix[i] - min_num;
}
}
}
return dp[0][1];
}
};

1140. 石子游戏 II (Medium)的更多相关文章

  1. BZOJ 1115: [POI2009]石子游戏Kam

    1115: [POI2009]石子游戏Kam Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 883  Solved: 545[Submit][Stat ...

  2. XDU 1161 - 科协的数字游戏II

    Problem 1161 - 科协的数字游戏II Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty: Total Submit: 112  ...

  3. Games:取石子游戏(POJ 1067)

    取石子游戏 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37662   Accepted: 12594 Descripti ...

  4. {CSDN}{英雄会}{砍树、石子游戏}

    砍树 思路: 可以将题目意图转化为:给定一棵树,求其中最接近总权值一半的子树. DFS求每个节点的所有子节点的权值和,遍历每个节点,最接近总权值一半的即为答案.复杂度O(N). 石子游戏: 思路: 一 ...

  5. HDU 2176 取(m堆)石子游戏(Nim)

    取(m堆)石子游戏 题意: Problem Description m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,1 ...

  6. HDU 2516 取石子游戏(斐波那契博弈)

    取石子游戏 Time Limit: 2000/1000 MS(Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...

  7. lintcode: 跳跃游戏 II

    跳跃游戏 II 给出一个非负整数数组,你最初定位在数组的第一个位置. 数组中的每个元素代表你在那个位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 样例 给出数组A =  ...

  8. hdu 1527 取石子游戏(Wythoff Game)

    题意:Wythoff Game 思路:Wythoff Game #include<iostream> #include<stdio.h> #include<math.h& ...

  9. HDU 2516 取石子游戏(FIB博弈)

    取石子游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  10. hdu 2176 取(m)石子游戏

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2176 题意分析:给出M堆石子,两人交替取子,给出先手能否胜利. 不能输出No, 能则输出Yes并给出第 ...

随机推荐

  1. 前端框架大比拼:2022年的Vue与React谁更胜一筹?

    携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 18 天,点击查看活动详情 前端框架经历了十多年的争奇斗艳百花齐放,经历了 JSP.jQuery.Ember.Angular.R ...

  2. vue vite 打包开启 gzip 部署 nginx 支持 gzip

    vite 打包开启 gzip 安装插件 npm i vite-plugin-compression --save-dev vite.config.js 配置 import { defineConfig ...

  3. linux启用ipv4转发功能

    一.临时生效,重启失效1.sysctl -w net.ipv4.ip_forward=12.echo 1 > /proc/sys/net/ipv4/ip_forward二.永久生效修改 /etc ...

  4. C# 调用Web Api通用方法

    1.通用方法 public class GetDataByWebApi { /// <summary> /// 通过web api获取数据的方法 /// </summary> ...

  5. crontal 计划任务

    crontab每分钟定时执行: */1 * * * * service mysqld restart //每隔1分钟执行一次 */10 * * * * service mysqld restart / ...

  6. python利用signal自定义函数超时机制

    利用signal模块,可以给函数设置一个超时时间(精确到秒),结合装饰器实现:超时时间内函数运行完成正常退出,超时时间内函数未运行完成则抛出Timeout异常. 1 # coding:utf8 2 i ...

  7. wireshark作业

    1Wireshark基本操作: 1.启动wireshark,正确选择混杂模式,访问任意网站: 2.设置过滤器呈现本地和该网站服务器之间的交互报文: 3.保存抓包结果文件.cap: 4.在作业纸上记录下 ...

  8. HANDLE和HMOUDLE、HWND讲解

    HWND是线程相关的,通常指明窗口句柄,通过句柄找到窗口所属进程和线程 Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄.系统对内核对象以链表的形式进行管理,载入到内存中的每一个内核 ...

  9. .Net core 基础 创建及Nlog

    一..Net Core 依赖注入 .net core3.1 之前的版本需要手动配置swagger.当前项目.net core5.0版本自动配置完成 跨域配置 1.下载依赖包 2.           ...

  10. 4-20mA换算为实际值公式

    Ov = [(Osh - Osl) * (Iv - Isl) / (Ish - Isl)] + Osl 实际工程量 = [((实际工程量)的高限 - (实际工程量)的低限)*(lv - 4) / (2 ...