问题描述

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. iOS开发 调试技巧

    1.普通断点 2.条件断点 3.全局断点 4.analyze 分析器 5.leaks 检查器 6.僵尸对象 7.lldb 命令 8.instruments 9.xcode视图调试

  2. 上传图片到Mongo数据库;从Mongo数据库下载图片显示到前端

    /** * 上传一个图片文件,保存到mongo数据库中 * @param doc * @param parent 文件所在的目录 * @param request * @return */ @Post ...

  3. Dockerfile自定义镜像

    一.镜像结构 镜像是将应用程序及其需要的系统函数库.环境.配置.依赖等打包而成 以MySQL为例: 如上图所示,镜像由多个层(Layer)构成,每个层包含不同的内容. 另外,某些层可以单独抽出,组成一 ...

  4. function 和mapped function的区别

    1 --在函数定义上使用mapped前缀将此函数标记为自动映射到集合上.这意味着,如果将集合作为函数的第一个参数,则该函数将在集合的元素上自动重复调用.这允许您定义脚本化函数,这些函数的行为方式与映射 ...

  5. CentOS7下MySQL数据的导入和导出

    一.数据导入 (1)进入mysql [root@localhost mysql]# mysql -u root -p (2)转到对应数据库下 mysql> use zenith_star; (3 ...

  6. Linux系统安全:SNAT和DNAT的实现

    一.SNAT1.SNAT实验目的公司内有2台机器,但是只有一个公网ip,利用SNAT技术实现2台私网地址都可以访问公网. 2.SNAT实验环境准备①三台服务器:PC1客户端.PC2网关.PC3服务端. ...

  7. C# 日期获得一天的起始时间

    dateTimePicker1.Value = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")); ...

  8. QT--弹出新的对话框 show()/exec()的区别

    show()显示非模态对话框,exec()显示模态对话框. 非模态对话框不会阻塞程序的线程,因此 如果你的对话框时创建在栈上,跳出作用域之后,对象便销毁了,对话框会一闪而过: 如果使用new在堆上创建 ...

  9. JAVA笔记_方法递归调用

    方法递归调用   简单地说递归调用就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂问题,同时可以让代码变得更加简洁. 递归调用执行机制案例1: /** * @ClassName ...

  10. sxt_(008_011)_servlet

    一.servlet简介 Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于 ...