只用一行代码就能搞定,博弈论究竟是什么神仙算法?

简介: 云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 博弈论是一门很庞大的学科,它算是数学的一个分支,也和运筹学甚至是经济学有关。虽然它严格说起来并不是算法领域的内容,但是有不少关于博弈论有趣的算法和问题。

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!


博弈论是一门很庞大的学科,它算是数学的一个分支,也和运筹学甚至是经济学有关。虽然它严格说起来并不是算法领域的内容,但是有不少关于博弈论有趣的算法和问题。关于博弈的相关理论从很早就已经有了雏形,但是正式构建理论成为一门学科是从计算机之父冯诺依曼开始的。从这点上来说也和计算机有点关系。

今天我们来聊聊博弈论当中最简单的巴什博奕(Bash Game)。

报数问题

说到巴什博奕就不能不提报数问题,它实在是太经典了,以至于我觉得你很有可能也听说过。题目是这样的,说是A和B两个人一起玩一个报数游戏,两个人轮流报数,每次最少报一个数,最多报5个数,第一个报到100的人获胜。如果你是先手的A,应该采取什么策略?

如果之前没有思考过这个问题或者是了解过博弈论的话,估计你可能会觉得这个问题很复杂,也很困难,应该没有什么好的办法。因为两个人每次都可以做好几种选择,每一种选择又会带来不同的选择,这样依次交错会带来大量的可能性。在这种情况下,似乎很难想出一个算法来解决问题。

报到100看不出来,我们缩小一下,如果报到6的人获胜呢?是不是就很明显了,先手的A不论采取什么策略都一定输。因为它不论报几个数,B都可以直接报到6。

既然报6个数的时候A一定必输,那么可以推导得到报的数如果是6的倍数A都一定必输。假设它在某一轮当中报了i,对方只要报6-i就行了。这样重复若干次之后最后一定会剩下6,那么就回到了上面说的最简单的情况。

假设我们开发出了一个state函数可以计算某个状态先手是必胜还是必败,我们用1表示先手必胜,0表示必败。那么显然state(0) = 0,state(6) = 0。由于不论先手在每一轮当中报几,后手都可以控制报一个和它加起来等于6的数,所以可以得到state(n) = state(n-6)。于是,我们可以推导出state(6n) = 0。

由于先手每次可以报1-5个数,当他面临一个6n+k的局面的时候,只要k不等于0。那么他就报k个数,就可以让局面转化成6n的必败局面给B。所以可以知道,除了6n的局面之外的所有局面都是先手必胜的。

我们用代码实现的话就只有一行:

def win_or_lose(n):
    return n % 0 != 0

博弈论的精髓在于对问题的分析,体现在代码上就是思维比较复杂,但是代码极为精简。

报数这个问题比较直观,所以找找规律仔细想想也是可以猜出答案来的。但如果我们包装一下,可能就不一样了。

打牌问题

这题源自HDU1847,题面是两个人打牌,一共有n张牌,双方轮流抓牌。规定每人每次抓牌的数量必须是2的幂,最后抓完排的人获胜。假设两人都是极端聪明,请问最后会是谁获胜。

假设两个人极端聪明,这是博弈论问题的前提,也就是说两个人都会采取最优策略。没有这个前提,就无法使用博弈论进行分析了,因为它就不再是单纯的数学问题了。

和上面的题目相比,这题变得复杂了。因为每个人采取的策略数量变了,之前是严格限制了只有5种可能,现在则变成了无数种。但其实这里使用了障眼法,藏了一个trick。

我们首先把2的幂都列出来,从2的0次方开始,分别是1, 2, 4, 8...。看到这个1和2不知道大家有没有什么想法,其实如果你稍微了解一点数论的话就会知道,2的幂一定不能被3整除。也就是说2的幂模3的结果只会有两种,也就是1或者是2。所以这道题其实和上面一题是一样的, 我们拿2的几次幂不重要,重要的是拿的数模3之后余下的几。

state(0) = 0,因为对方已经拿完了。那么state(1) = state(2) = 1,只剩一张或者两张牌的时候可以一次全拿完。state(3) = 0,因为无法一次拿完。我们推广可以得到state(3n) = 0。也就是3的倍数对于先手是必败的。由于我们刚才说了,2的幂模3一定是1或者是2。所以可以得到,对于先手来说,只要面临的状态不是3的倍数,就一定必胜。因为他一定可以找到一个2的幂,使得拿完之后留下3的倍数给对方。

分析完了之后,代码又只有一行:

def win_or_lose(n):
    return n % 3 != 0

总结

巴什博奕的问题很简单,一旦摸清楚了套路之后,这一系列类似的问题都手到擒来。但是要注意的是,面临巴什博奕的问题,我们不能只是简单地理解成是凑成一个数,或者是找到一个必胜或者必败的策略。而是要从状态的角度去分析它,究竟什么样的状态是必胜或者是必败的,状态之间又存在什么样的转移关系。

从这点上来看似乎又有点动态规划的意思,但不一样的是动态规划算法解决的都是边界有限的问题。而博弈论当中有的时候策略或者是状态可能是无限的,但是两者的确有相通的部分。巴什博奕只是博弈论算法当中最简单的算法,后面我们还会继续研究其他更复杂一些的博弈论问题。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-06-13
本文作者:承志
本文来自:“掘金”,了解相关信息可以关注“掘金”

相关文章
|
12天前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
13天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
37 1
|
21天前
|
存储 缓存 算法
通过优化算法和代码结构来提升易语言程序的执行效率
通过优化算法和代码结构来提升易语言程序的执行效率
|
28天前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
1月前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
41 3
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
2月前
|
存储 缓存 算法
如何通过优化算法和代码结构来提升易语言程序的执行效率?
如何通过优化算法和代码结构来提升易语言程序的执行效率?
|
2月前
|
搜索推荐
插入排序算法的讲解和代码
【10月更文挑战第12天】插入排序是一种基础的排序算法,理解和掌握它对于学习其他排序算法以及数据结构都具有重要意义。你可以通过实际操作和分析,进一步深入了解插入排序的特点和应用场景,以便在实际编程中更好地运用它。
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
【自然语言处理】TF-IDF算法在人工智能方面的应用,附带代码
TF-IDF算法在人工智能领域,特别是自然语言处理(NLP)和信息检索中,被广泛用于特征提取和文本表示。以下是一个使用Python的scikit-learn库实现TF-IDF算法的简单示例,并展示如何将其应用于文本数据。
277 65
|
2月前
|
缓存 分布式计算 监控
优化算法和代码需要注意什么
【10月更文挑战第20天】优化算法和代码需要注意什么
22 0