【PE806】Nim on Towers of Hanoi(汉诺塔游戏,生成函数)
PE:Project Euler
题意:
汉诺塔游戏是如下的问题:有三根柱子,第一根柱子套有 n n n 个圆盘,圆盘从上往下半径递增。每次操作可以把套在某根柱子上的最上面的那个圆盘移到另一个柱子上。但需保证过程中每根柱子都始终满足大盘在下小盘在上。现要在最小的步数内,将这 n n n 个圆盘仍按从上往下半径递增的顺序,全部套在第三根柱子上。
现在按最优策略进行汉诺塔游戏。过程中,设 a , b , c a,b,c a,b,c 是当前三根柱子上的盘子个数,若 a ⊕ b ⊕ c = 0 a\oplus b\oplus c=0 a⊕b⊕c=0,那么让答案加等于当前的步数。求最后答案。
n = 1 0 5 n=10^5 n=105。
题解:
首先得知道汉诺塔游戏的最优策略是啥。设 n n n 个盘子的答案为 f n f_n fn。
考虑最大的那个盘子,即第 n n n 个盘子。显然存在一个时刻把它移到第三根柱子并固定下来永远不动。那么此时需要满足:第一根柱子只有第 n n n 个盘子、第二根柱子按半径递增套着剩下 n − 1 n-1 n−1 个盘子、第三根柱子为空。
那么我们需要把原来第一根柱子上的 n − 1 n-1 n−1 个盘子全部移到第二根柱子,这个过程的步数下界是 f n − 1 f_{n-1} fn−1(显然第一根柱子上的第 n n n 个盘子并不会使得步数在 f n − 1 f_{n-1} fn−1 的基础上变得更少),而显然这个步数下界是可以达到的(忽略第 n n n 个盘子即可,因为它是全局最大的)。
同理可以证明,最优方案是用 f n − 1 f_{n-1} fn−1 步把第二根柱子上的 n − 1 n-1 n−1 个盘子移到第三根柱子上。
从而得到 f n = 2 f n − 1 + 1 = 2 n − 1 f_n=2f_{n-1}+1=2^n-1 fn=2fn−1+1=2n−1,以及最优策略(显然最优策略唯一,我们不可能在动 n − 1 n-1 n−1 个盘子的时候动第 n n n 个盘子,这样会使答案变劣)。
现在转到另一个问题:我们先考虑满足 a + b + c = n a+b+c=n a+b+c=n 且 a ⊕ b ⊕ c = 0 a\oplus b\oplus c=0 a⊕b⊕c=0 的 ( a , b , c ) (a,b,c) (a,b,c) 应满足什么条件。
可以归纳证明,在 a ⊕ b ⊕ c = 0 a\oplus b\oplus c=0 a⊕b⊕c=0 的前提下, a + b + c = n a+b+c=n a+b+c=n 过程中每次进位不超过 1 1 1。同时,可以根据 a + b + c a+b+c a+b+c 在某位上的值确定上一位具体往这一位进的是 0 0 0 还是 1 1 1。同时,若上一位进了 0 0 0,那么上一位必定是三个 0 0 0;若上一位进了 1 1 1,那么上一位 a , b , c a,b,c a,b,c 中必是两个 1 1 1 一个 0 0 0。
那么可以在 O ( 3 popc ( n ) ) O(3^{\operatorname{popc}(n)}) O(3popc(n)) 的时间复杂度内枚举每一种 ( a , b , c ) (a,b,c) (a,b,c)。
又注意到若 ( a , b , c ) (a,b,c) (a,b,c) 在第 x x x 步出现了,那么对称地有 ( c , b , a ) (c,b,a) (c,b,a) 在第 2 n − 1 − x 2^{n}-1-x 2n−1−x 步出现。
于是,只需对于某个 ( a , b , c ) (a,b,c) (a,b,c),知道它在过程中出现了多少次即可。
考虑 DP,设 f a , b , c f_{a,b,c} fa,b,c 表示在 n = a + b + c n=a+b+c n=a+b+c 的汉诺塔游戏中, ( a , b , c ) (a,b,c) (a,b,c) 在过程中出现的次数。于是 f a , b , c = f c , b , a f_{a,b,c}=f_{c,b,a} fa,b,c=fc,b,a。
考虑 ( a , b , c ) (a,b,c) (a,b,c) 出现时,第 n n n 个盘子的位置,若它在第一根柱子上,那么方案数为 f a − 1 , c , b f_{a-1,c,b} fa−1,c,b;若它在第三根柱子上,那么方案数为 f b , a , c − 1 f_{b,a,c-1} fb,a,c−1。从而 f a , b , c = f a − 1 , c , b + f b , a , c − 1 f_{a,b,c}=f_{a-1,c,b}+f_{b,a,c-1} fa,b,c=fa−1,c,b+fb,a,c−1。
设 f f f 对应的生成函数为 F ( x , y , z ) F(x,y,z) F(x,y,z)。那么上式意味着 F ( x , y , z ) = x F ( x , z , y ) + z F ( y , x , z ) + 1 F(x,y,z)=xF(x,z,y)+zF(y,x,z)+1 F(x,y,z)=xF(x,z,y)+zF(y,x,z)+1,加一是因为 f 0 , 0 , 0 = 1 f_{0,0,0}=1 f0,0,0=1。
这个生成函数和一般的生成函数不太一样,因为它涉及到下标的位置交换,即维度与维度之间的交换。那么仅靠这一条方程是不够的,我们要把其他对称的方程都写出来。
令 F x = F ( y , x , z ) = F ( z , x , y ) F_x=F(y,x,z)=F(z,x,y) Fx=F(y,x,z)=F(z,x,y), F y = F ( x , y , z ) = F ( z , y , x ) F_y=F(x,y,z)=F(z,y,x) Fy=F(x,y,z)=F(z,y,x), F z = F ( x , z , y ) = F ( y , z , x ) F_z=F(x,z,y)=F(y,z,x) Fz=F(x,z,y)=F(y,z,x)。类似地我们可以得出三条等式:
F y = x F z + z F x + 1 F x = y F z + z F y + 1 F z = x F y + y F x + 1 F_y=xF_z+zF_x+1\\ F_x=yF_z+zF_y+1\\ F_z=xF_y+yF_x+1 Fy=xFz+zFx+1Fx=yFz+zFy+1Fz=xFy+yFx+1
解得 F ( x , y , z ) = F y = ( 1 + y ) ( 1 + x − y + z ) 1 − x 2 − y 2 − z 2 − 2 x y z = ( 1 + y ) ( 1 + x − y + z ) ∑ i = 0 ∞ ( x 2 + y 2 + z 2 + 2 x y z ) i F(x,y,z)=F_y=\dfrac{(1+y)(1+x-y+z)}{1-x^2-y^2-z^2-2xyz}=(1+y)(1+x-y+z)\sum\limits_{i=0}^{\infty}(x^2+y^2+z^2+2xyz)^i F(x,y,z)=Fy=1−x2−y2−z2−2xyz(1+y)(1+x−y+z)=(1+y)(1+x−y+z)i=0∑∞(x2+y2+z2+2xyz)i。
把 ( 1 + y ) ( 1 + x − y + z ) (1+y)(1+x-y+z) (1+y)(1+x−y+z) 展开,再枚举 i i i,要算的就是 [ x a y b z c ] ( x 2 + y 2 + z 2 + 2 x y z ) i [x^ay^bz^c](x^2+y^2+z^2+2xyz)^i [xaybzc](x2+y2+z2+2xyz)i。这个东西可以 O ( 1 ) O(1) O(1) 算:考虑 2 x y z 2xyz 2xyz 这一项在乘积中的幂次 k k k,那么需要满足 3 k + 2 ( i − k ) = a + b + c 3k+2(i-k)=a+b+c 3k+2(i−k)=a+b+c,容易解出 k k k,然后容易解出 x 2 , y 2 , z 2 x^2,y^2,z^2 x2,y2,z2 分别在乘积中的幂次,然后用组合数一算就好了。
时间复杂度 O ( 3 popc ( n ) × n ) O(3^{\operatorname{popc}(n)}\times n) O(3popc(n)×n)。
【PE806】Nim on Towers of Hanoi(汉诺塔游戏,生成函数)相关推荐
- 递归算法 —— Hanoi汉诺塔游戏
前言 博客主页:干脆面la的主页 gitte链接:干脆面la的gitee仓库 刚学习完递归函数接触汉诺塔问题的时候,汉诺塔问题困扰了我很久.博主花了很长时间理解这道题目,因此整理出了用递归解决汉诺塔问 ...
- Strange Towers of Hanoi 汉诺塔问题及其升级(递推)四个汉诺塔问题
今天学习递推的汉诺塔问题,非常的有趣 文章目录 1.汉诺塔问题来源 分析 2.Strange Towers of Hanoi[DP][递推] 题目大意: 思考 解题步骤: 1.汉诺塔问题来源 汉诺塔( ...
- c语言递归求塔移动次数,【C语言】Hanoi(汉诺)塔问题,求移动盘子的步骤(递归法)...
所有的循环算法都可以用递归实现,反之不成立,这足以证明递归的重要性! Hanoi(汉诺)塔问题.古代有一个焚塔,塔内有3个座A,B,C,开始时A座上有64个盘子,盘子大小不等,大的在上,小的在下,有一 ...
- C++Tower of Hanoi汉诺塔的实现算法(附完整源码)
C++Tower of Hanoi汉诺塔的实现算法 C++Tower of Hanoi汉诺塔的实现算法完整源码(定义,实现,main函数测试) C++Tower of Hanoi汉诺塔的实现算法完整源 ...
- Hanoi(汉诺)塔问题
问题描述: Hanoi(汉诺)塔问题.古代有一个梵塔,塔内有3个座A,B,C,开始时A座有n个盘子,盘子大小不等,大的在下,小的在上.有一个老和尚想把这n个盘子,从A座移动到C座,但是每次只允许移动一 ...
- C语言---移盘子----Hanoi(汉诺)塔问题,显示移动盘子的步骤
C语言-移盘子----Hanoi(汉诺)塔问题,显示移动盘子的步骤 在学习递归的过程中,Hanoi(汉诺)塔问题是避开不了的,很多新手在这儿一脸懵. 我们先简单介绍一些Hanoi(汉诺)塔问题到底是个 ...
- 递归算法以及Hanoi(汉诺)塔问题及其详细解释
递归在算法中是非常重要的,可以说几乎所有的循环算法都可以用递归来实现,这足以体现递归的重要性,利用递归的条件一般为一下: 定义是递归的 像有些数学函数就是递归定义的,例如大家熟悉的阶层函数: 2.利用 ...
- 【使用递归玩通关汉诺塔游戏】算法01-递归(斐波那契数列、汉罗塔问题)-java实现
递归 定义:在一个方法(函数)的内部调用该方法(函数)本身的编程方式 简而言之就是 "自己调自己" 在玩游戏之前让我们先对递归有一个简单的了解吧! 5.1 递归简介 递归必须有一个 ...
- Py:递归求解汉诺塔,简单的几行编程可以搞定很高层的三柱汉诺塔游戏
Py:递归求解汉诺塔,简单的几行编程可以搞定很高层的三柱汉诺塔游戏 目录 输出结果 核心代码 输出结果 核心代码 def hanoi(n,x,y,z):if n==1:print(x,'--→',z) ...
最新文章
- 数据分析索引总结(下)Pandas索引技巧
- 目标检测:Anchor-Free时代
- C# 中奇妙的函数–6. 五个序列聚合运算(Sum, Average, Min, Max,Aggregate)
- 五、【SAP-PM模块】服务采购业务流程
- 用JavaScript实现2+2=5的奥秘
- 面试题如何实现一个IOC容器
- Spring boot整合rabbitmq
- Autolayout的简单介绍和示例代码
- CString,string,char*,比较
- 视图查询sql_视图 索引
- 特征值和特征向量(整理)
- libtool: Version mismatch error. This is libtool 2.4.6, but the definition of this LT_INIT
- ffmpeg 音乐循环_背景音乐自动循环播放
- 鸿蒙系统下载地址_华为鸿蒙代码全开源
- 解析信号与希尔伯特变换
- 移植conda环境到另一台服务器上
- PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)
- 如何录制游戏视频中的音频
- 单片机24秒倒计时c语言,基于51单片机的篮球24秒倒计时器
- 3、TM4之GPIO的输入输出
热门文章
- brew install node 报错:Error: No such file or directory @ dir_chdir Bottle installation failed:
- 企业管理之如何理解企业战略
- 不知道密码,怎么打开PPT文件
- 我是如何从写不出来到写二十万字的稿的
- springcloud学习笔记(八)SpringCloud集成zuul路由(一)
- 盐城工学院c语言重修试卷,大学物理期末试卷(盐城工学院)
- 第一课 初识Photoshop Photoshop的诞生和发展
- Day04:编程中的“真”“假”?
- UPS不间断电源工作方式几点说明
- Python 建立流域三层蒸发和蓄满产流模型(二水源划分)