问题描述

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. Linux与Windows对比

    1. 前言 Windows是微软为个人台式机/设备或电脑(PC)开发的一系列操作系统.计算机操作系统(OS).每个操作系统都有一个图形用户界面(GUI),桌面允许用户查看所有文件.视频等.Window ...

  2. 【面试必备】 【ES6】学Vue前必须掌握的内容(上)

    变量声明 采用 let 和 const 分别声明变量和常量. 不用var所以不存在变量提升. 解构 ① 数组解构[ ] 等号左边允许存在默认值.变量的取值按照顺序. //之前的写法 var arr=[ ...

  3. MongoDB升级

    因业务需要所以需要对mongoDB客户端jar包升级,在此记录一些过程 1.jar包替换,引入依赖 3.2.2: mongo-java-driver     |     4.6.1: mongo-dr ...

  4. VLC播放器 for Mac OS X

    ​ VLC 是一款自由.开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD.音频 CD.VCD 及各类流媒体协议. https://www.videolan.org/vlc/down ...

  5. Linux系统Shell脚本第一章:Shell脚本基础及时间同步

    目录 一.Shell脚本基础 1.Shell作用 2.什么是Shell脚本及处理逻辑 3.shell脚本基本格式 4. shell脚本执行方式 5.实操演示 二.Shell脚本中的变量 1.变量的作用 ...

  6. EF中使用SqlBulkCopy

    using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using S ...

  7. 学习lua-06,异常提示,错误处理

    addNum = function(a, b) assert(type(a) == 'string','a必须是一个字符串') assert(type(b) == 'string','b必须是一个字符 ...

  8. Thread记录

    项目用到了线程 所以写出来留作以后复习线程Thread类包含在System.Threading命名空间有关线程的操作主要包含在这个类中现在总结一下Thread的常用方法和属性 Start([参数])/ ...

  9. [iOS]获取地理位置信息

    1.在工程的 info.plist 文件中增加两个key( 右键 - Add Row ) Privacy - Location Always and When In Use Usage Descrip ...

  10. React-Navigation 5.x 的 demo案例

    一. stack路由结构的一些效果 (1)横向过渡动画 (2)整个选项卡样式修饰 最终实现效果:动态图 以上两个功能实现都很简单,我测试时,关注了一个问题,navigation 丢失.stackNav ...