[LintCode] Coins in a Line II 一条线上的硬币之二
There are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins.
Could you please decide the first player will win or lose?
Given values array A = [1,2,2], return true.
Given A = [1,2,4], return false.
这道题是之前那道Coins in a Line的延伸,由于每个硬币的面值不同,所以那道题的数学解法就不行了,这里我们需要使用一种方法叫做极小化极大算法Minimax,这是博弈论中比较经典的一种思想,LeetCode上有一道需要用这种思路解的题Guess Number Higher or Lower II。这道题如果没有接触过相类似的题,感觉还是蛮有难度的。我们需要用DP来解,我们定义一个一维数组dp,其中dp[i]表示从i到end可取的最大钱数,大小比values数组多出一位,若n为values的长度,那么dp[n]先初始化为0。我们是从后往前推,我们想如果是values数组的最后一位,及i = n-1时,此时dp[n-1]应该初始化为values[n-1],因为拿了肯定比不拿大,钱又没有负面额;那么继续往前推,当i=n-2时,dp[n-2]应该初始化为values[n-2]+values[n-1],应为最多可以拿两个,所以最大值肯定是两个都拿;当i=n-3时,dp[n-3]应该初始化为values[n-3]+values[n-2],因为此时还剩三个硬币,你若只拿一个,那么就会给对手留两个,当然不行,所以自己要拿两个,只能给对手留一个,那么到目前位置初始化的步骤就完成了,下面就需要找递推式了:
当我们处在i处时,我们有两种选择,拿一个还是拿两个硬币,我们现在分情况讨论:
1. 当我们只拿一个硬币values[i]时,那么对手有两种选择,拿一个硬币values[i+1],或者拿两个硬币values[i+1] + values[i+2]
a) 当对手只拿一个硬币values[i+1]时,我们只能从i+2到end之间来取硬币,所以我们能拿到的最大硬币数为dp[i+2]
b) 当对手拿两个硬币values[i+1] + values[i+2]时,我们只能从i+3到end之间来取硬币,所以我们能拿到的最大硬币数为dp[i+3]
由于对手的目的是让我们拿较小的硬币,所以我们只能拿dp[i+2]和dp[i+3]中较小的一个,所以对于我们只拿一个硬币的情况,我们能拿到的最大钱数为values[i] + min(dp[i+2], dp[i+3])
2. 当我们拿两个硬币values[i] + values[i + 1]时,那么对手有两种选择,拿一个硬币values[i+2],或者拿两个硬币values[i+2] + values[i+3]
a) 当对手只拿一个硬币values[i+2]时,我们只能从i+3到end之间来取硬币,所以我们能拿到的最大硬币数为dp[i+3]
b) 当对手拿两个硬币values[i+2] + values[i+3]时,我们只能从i+4到end之间来取硬币,所以我们能拿到的最大硬币数为dp[i+4]
由于对手的目的是让我们拿较小的硬币,所以我们只能拿dp[i+3]和dp[i+4]中较小的一个,所以对于我们只拿一个硬币的情况,我们能拿到的最大钱数为values[i] + values[i + 1] + min(dp[i+3], dp[i+4])
综上所述,递推式就有了 dp[i] = max(values[i] + min(dp[i+2], dp[i+3]), values[i] + values[i + 1] + min(dp[i+3], dp[i+4]))
这样当我们算出了dp[0],知道了第一个玩家能取出的最大钱数,我们只需要算出总钱数,然后就能计算出另一个玩家能取出的钱数,二者比较就知道第一个玩家能否赢了,参见代码如下:
class Solution {
public:
/**
* @param values: a vector of integers
* @return: a boolean which equals to true if the first player will win
*/
bool firstWillWin(vector<int> &values) {
if (values.size() <= ) return true;
int n = values.size(), sum = ;
vector<int> dp(n + , );
dp[n - ] = values[n - ];
dp[n - ] = values[n - ] + values[n - ];
dp[n - ] = values[n - ] + values[n - ];
for (int i = n - ; i >= ; --i) {
dp[i] = max(values[i] + min(dp[i + ], dp[i + ]), values[i] + values[i + ] + min(dp[i + ], dp[i + ]));
}
for (int d : values) {
sum += d;
}
return sum - dp[] < dp[];
}
};
类似题目:
Guess Number Higher or Lower II
参考资料:
http://www.cnblogs.com/theskulls/p/4963317.html
[LintCode] Coins in a Line II 一条线上的硬币之二的更多相关文章
- [LintCode] Coins in a Line 一条线上的硬币
There are n coins in a line. Two players take turns to take one or two coins from right side until t ...
- LintCode "Coins in a Line II" !
Nice one to learn: DP + Game Theoryhttps://lefttree.gitbooks.io/leetcode/content/dynamicProgramming2 ...
- LintCode: coins in a line I
有 n 个硬币排成一条线.两个参赛者轮流从右边依次拿走 1 或 2 个硬币,直到没有硬币为止.拿到最后一枚硬币的人获胜. 请判定 第一个玩家 是输还是赢? n = 1, 返回 true.n = 2, ...
- lintcode 394. Coins in a Line 、leetcode 292. Nim Game 、lintcode 395. Coins in a Line II
变型:如果是最后拿走所有石子那个人输,则f[0] = true 394. Coins in a Line dp[n]表示n个石子,先手的人,是必胜还是必输.拿1个石子,2个石子之后都是必胜,则当前必败 ...
- LeetCode:149_Max Points on a line | 寻找一条直线上最多点的数量 | Hard
题目:Max Points on a line Given n points on a 2D plane, find the maximum number of points that lie on ...
- Lintcode395 Coins in a Line II solution 题解
[题目描述] There are n coins with different value in a line. Two players take turns to take one or two c ...
- Coins in a Line II
There are n coins with different value in a line. Two players take turns to take one or two coins fr ...
- 395. Coins in a Line II
最后更新 这个题做得也不好,dp[n]尝试写了几下,不太对. 应该是类似于gem theory的题. 当只有1个硬币剩下的时候直接拿走,不BB. 剩俩的时候也都拿了.. dp[n]表示剩下多少个硬币. ...
- LintCode "Coins in a Line III" !!
https://codesolutiony.wordpress.com/2015/05/24/lintcode-coins-in-a-line-iii/ A very juicy one! Deser ...
随机推荐
- 一个linux的样本分析
不久前收到的一个linux样本,之前linux平台下的样本见得并不多,正好做个记录. 样本启动之后,会将自身重命名拷贝到/usr/bin下,并删除自身,如此处就将自身文件amdhzbenfi命名为us ...
- zookeeper + LevelDB + ActiveMQ实现消息队列高可用
通过集群实现消息队列高可用. 消息队列在项目中存储订单.邮件通知.数据分发等重要信息,故对消息队列稳定可用性有高要求. 现在通过zookeeper选取activemq leader的形式实现当某个ac ...
- jQuery实现等比例缩放大图片
在布局页面时,有时会遇到大图片将页面容器“撑破”的情况,尤其是加载外链图片(通常是通过采集的外站的图片).那么本文将为您讲述使用jQuery如何按比例缩放大图片,让大图片自适应页面布局. 通常我们 ...
- wpf Popup Win8.0 bug HorizontalOffset 弹出位置偏移
问题描述参考 wpf 客户端[JDAgent桌面助手]开发详解(四) popup控件的win8.0的bug 当开发完程序后,我们在多操作系统测试时候发现:win8.0 系统中 popup 弹出的位置 ...
- 在Dreamweaver中安装Emmet(zen-coding)
在http://www.adobe.com/exchange/em_download/地址下下载好Emmet扩展插件,然后在Dreamweaver找到菜单栏中命令>扩展管理>文件,找到以后 ...
- OpenCV 线性混合(4)
带滚动条的线性混合示例: #include "stdafx.h" #include<iostream> #include<thread> #incl ...
- C# 开发积累(1)
EntityFramework批量增加时报"...请在调用 AcceptChanges 之前,确保键值是唯一的" http://www.xinglongjian.com/i ...
- Storm TimeCacheMap RotatingMap源码分析
TimeCacheMap是Twitter Storm里面一个类, Storm使用它来保存那些最近活跃的对象,并且可以自动删除那些已经过期的对象. 不过在storm0.8之后TimeCacheMap被弃 ...
- 如何处理js的跨域问题
在bill.mail.10086.cn域内访问smsrebuild1.mail.10086.cn下的接口出现“阻止跨域源请求” 例如: URL 说明 是否允许通信 http://www.a.com/a ...
- underscore.js依赖库函数分析二(查找)
查找: 在underscore.js封装了对dom查找的操作,find()和filter()函数,find()函数的查找操作是返回首个与条件相符的元素值,filter()函数是找到与条件相符的所有元素 ...