除数博弈

除数博弈(Divisor Game)是我在leetcode上遇到的一个题目,它的描述如下:

Alice and Bob take turns playing a game, with Alice starting first.

Initially, there is a number N on the chalkboard.  On each player's turn, that player makes a move consisting of:

Choosing any x with 0 < x < N and N % x == 0.
Replacing the number N on the chalkboard with N - x.
Also, if a player cannot make a move, they lose the game.

Return True if and only if Alice wins the game, assuming both players play optimally.

来源:力扣(LeetCode)
链接:单击这里

中文是:

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。

给出的示例是:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

题目理解

做题的第一步肯定是要理解题意。

首先,游戏本身规则只有两条,是很简单易懂的,关键在于如何选择一个数x使自己能够获胜

其中,题目给出了一个限定条件:假设两个玩家都以最佳状态参与游戏(play optimally)。这是一个很重要的条件,这告诉我们玩家在选择x时不是随机的(都选1 或者 选尽可能大的因数 等等),因为这么选似乎与自己的胜利没多大关系。他们是有针对性地选择一个有利于自己的数字。

从上述角度思考,可以大致得到解决题目的方向。

动态规划解法

如果假设给定任意一个整数N,我们要想取得胜利,必须找到一个数x,它既是N的因数,又使得N-x的结果是输的。

也就是说,我们只要找到了这个数x,就可以选择它,然后扔给对方N-x让他输掉。相反地,如果我们找不到,那么我们就是输家。

由于要用到以前的状态(即N-x是赢还是输),所以我们自然想到了动态规划。做法如下:

1. 动态规划的各状态为拿到该数会输还是赢,对应False和True。易知dp[1] = False。由此建立了边界条件。

2. 对于一个数N,可以先初始化其状态为False。要想求得它的真实状态,则要从1到N-1的循环中寻找它的因数( N%x==0 ? ),并判断N-x的状态是否为False,若是,这个数N的状态为True。若没有,则维持原状态False。

最后可以求得N的状态,通过判断N的状态是True还是False来给出胜负与否。

代码如下:

bool divisorGame(int N)
{bool dp[N + 1]; // 多开一个好看一点dp[1] = false;for (int i = 2; i <= N; i++) // 建立状态数组{dp[i] = false;for (int j = 1; j < i; j++){if (i % j == 0 && dp[i - j] == false) //满足那两个条件才能获胜{dp[i] = true;break;}}}return dp[N]; // 返回第N个状态
}

代码的时间复杂度较高,只能击败大概20-30%的提交者。那么是否还有一些潜在规律还没有被发现?是否能够进一步优化算法呢?答案是肯定的,要想击败100%,你只需要一行代码。

归纳法

归纳法的思路跟动态规划很像,也是从第1个状态往后推,一直推到第N个,唯一不同的是,它发现了两条潜在的定律:

  • 任何奇数的因数都是奇数,不可能有偶数,因此奇数减去任意一个因数必然得到偶数
  • 任何偶数的因数可以是奇数也可以是偶数,但是我们只要取因数1,减去1就必然得到一个奇数

这两条定律有什么用呢?

考虑到边界状态1是False,那么我拿到2,我就可以减1让你输,因此2是True。

再考虑3,根据规律一,你必然扔给给对方一个偶数,偶数目前只有2,对方拿到2是必然赢的,所以你会输。

再考虑4,因为3是肯定输的,那我就故意减1,让你输,所以4是True。

再考虑5,因为处理后会给对方偶数,偶数又是必胜的,所以5是会输的。

……

由此,我们就发现了这个游戏的奥秘,你拿到奇数,你必然会输(若对方知道规律),因为你处理后只能给对方偶数,如果对方知道奇数会输,偶数会赢,必然返你一个奇数(减1必然是奇数),你无法逃出规律一的魔咒,只能等着输。反之亦然。

因为题目中说,双方都会play optimally。那么代码就很简单了:

bool divisorGame(int N)
{return N % 2 == 0; // 判断是否为偶数
}

不妨在生活中玩一下

当你知道归纳法的规律,你就能对一个不知道规律的对手操纵游戏的进行,让对方一直输下去……直到他也可能摸索出了规律哈哈。

一个有趣的博弈或推理游戏——除数博弈(动态规划与归纳法)相关推荐

  1. python实现简单小游戏_用python开发一个有趣的猜数字小游戏(实现简单的GUI界面学习)...

    文章目录 用python开发一个有趣的猜数字小游戏 用于字符串的格式化,通过 {} 和 : 来代替以前的 % 1. python的GUI编程 1.1 pythonGUI常用库对比 Python 提供了 ...

  2. 教你如何用C语言设计一个有趣的猜数字小游戏

    目录 前言 猜数字游戏 打印菜单 处理玩家选择的操作 编写猜数字游戏函数 游戏中要猜数字从哪来?(配置随机数生成器) 时间戳 开始生成随机数 game函数内部编写 完整代码 总结 前言 好久不见,今天 ...

  3. 【摸鱼系列】如何用Python做一个有趣的Loading彩蛋游戏~

    嗨害大家好鸭!我是小熊猫❤ 不知道大家有没有在摸鱼的时候玩过它~ 这是谷歌流量器中很有名的彩蛋: 当你网络出现问题时,就会出现一个"小恐龙游戏". 当然你如果想要直接进行游戏,可以 ...

  4. 一个有趣的仿cmd小游戏(原创)

    背景 大家好鸭!不知道大家熟不熟悉这张图片呢? 没错!这就是系统里的cmd程序! 不过我倒是觉得它只能用来管理后台太枯燥了,于是,我自己原创了一个仿cmd的小游戏! 简单介绍 我的仿cmd小游戏里即可 ...

  5. LeetCode 810. 黑板异或游戏(博弈推理)

    1. 题目 一个黑板上写着一个非负整数数组 nums[i] . 小红和小明轮流从黑板上擦掉一个数字,小红先手. 如果擦除一个数字后,剩余的所有数字按位异或运算得出的结果等于 0 的话,当前玩家游戏失败 ...

  6. Py之pygame:有趣好玩——利用pygame库实现一个移动底座弹球的小游戏

    Py之pygame:有趣好玩--利用pygame库实现一个移动底座弹球的小游戏 目录 输出结果 实现代码 输出结果 实现代码 # -*- coding: utf-8 -*-#Py之pygame:有趣好 ...

  7. pygame小游戏代码_Py之pygame:有趣好玩——利用pygame库实现一个移动底座弹球的小游戏...

    Py之pygame:有趣好玩--利用pygame库实现一个移动底座弹球的小游戏 目录 输出结果 实现代码 输出结果 ​ 实现代码 # -*- coding: utf-8 -*-#Py之pygame:有 ...

  8. Python入门教程实战,用Python做一个有趣的拿石子游戏

    今天以一个小实例带你入门Python,编写一个叫"拿石子"的小游戏,让你可以与电脑对弈. 拿石子游戏规则很简单,一开始有一定数量的石子(假如是10),然后两人轮流从石子堆中取走一定 ...

  9. LeetCode 1025. 除数博弈(动态规划)

    1. 题目 爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需要执行以下操作: 选出任一 x,满足 0 < x < N 且 N ...

最新文章

  1. 代码实例--请求的转发:RequestDispatcher对象处理请求的两个方法--forward和include
  2. Winform中设置ZedGraph因设置小刻度导致的竖直虚线显示过多
  3. Vue.js2.0开发环境搭建(二)
  4. 什么是mysql的主从复制?
  5. python tkinter 输入数字 小数_Python3 tkinter基础 Entry validate isdigit 只能输入数字的输入框...
  6. 【机器学习】AI系统实时监测独居老人症状
  7. Java集合转化为数组
  8. ansible常用命令
  9. LinkedList作者说他自己都不用LinkedList?看完给我整不会了。。
  10. C#OOP之一面向对象简介
  11. Altium Designer 17 安装方法及步骤
  12. 冰点还原无法修改计算机时间,安装冰点还原后无法更改系统时间怎么办
  13. 拿下国产高端市场第一背后,vivo与苹果、华为的共性
  14. html5 粽子飘落,飘落的丁香花阅读*
  15. Windows取证一
  16. 2019春运抢票攻略:凭借单身三十年的手速干死一批黄牛党
  17. [MEM]Backdoor Access Memory
  18. 讯飞AIUI平台语义理解配置全攻略——以Android版AIUI SDK为例
  19. c语言kbhit函数头文件,有没有办法在标准C中替换kbhit()和getch()函数?
  20. git 解决push报错:[rejected] master -> master (fetch first)

热门文章

  1. picker多选 vant_vant框架picker选择器形式列表,以及封装
  2. LaTeX不显示页码_老板让我给PPT加页码,我哭了!
  3. 多款AE字幕条模板动画
  4. Echarts 横坐标时间轴,相同的年份只显示第一个,方案记录
  5. 05-现代威胁环境下的10个SIEM用例
  6. 云开发小课-OA 物品领用
  7. 新手在IDEA如何创建一个Web项目
  8. 1688获得店铺的所有商品
  9. 【转】关于usr/bin/ld: cannot find -lxxx问题总结
  10. 大数据就业:学完大数据怎样就业