这题不复杂,只需将问题拆解成N个子问题(N为题目中程序输入的值,即盘子个数)。
汉诺塔一般思路为:将最大盘作为一个整体,将最大盘上面的所有盘子(N-1个盘)作为一个整体,分别进行移动。
因此,子问题就是最大盘(后文称为底部)和剩下的N-1个盘(后文称为顶部)这两个整体的移动规律。
一个盘子的情况
根据题目规定,易知该情况下,只有底部,没有顶部,从A移动到B需要1次操作(A→B),从A移动到C需要2次操作(A→B,B→C)。
设函数AB(N)为把N个盘从A移动到B需要操作的次数,函数AC(N)为把N个盘从A移动到C需要操作的次数。
因此我们可以记为当N=1时,AB(1)=1,AC(1)=2。
两个或两个以上盘子的情况
A移动到B时
首先需要把顶部从A移到C,再把底部从A移到B,最后把顶部从C移到B。
一共会有5次操作,即1、A→B,2、B→C,3、A→B,4、C→A,5、A→B。
实际上,AB(N)可以视为是由3个子问题组成的,即1、顶部移动两次,2、底部移动一次,3、顶部移动两次;
子问题1实际上是AC(N-1)的问题;
子问题2由于底部只有一个盘,所以子问题2的值恒等于AB(1),即值为1;
子问题3实际上也是AC(N-1)的问题;
所以AB(N)=AC(N-1)+1+AC(N-1)
简化一下,AB(N)=2AC(N-1)+1
可结合下图理解,其中绿色部分为顶部,橙色部分为底部:
A移动到C时
首先将顶部从A移到C,再将底部从A移到B,再将顶部从C移到A,再将底部从B移到C,最后将顶部从A移到C。
一共有7次操作,即:1、A→B,2、B→C,3、A→B,4、C→A,5、B→C,6、A→B,7、B→C。
同样的,AC(N)也可以视为由5个子问题组成,即:1、顶部移动两次,2、底部移动一次,3、顶部移动一次,
4、底部移动一次,5、顶部移动两次;
子问题1实际上是AC(N-1)的问题;
子问题2由于底部只有一个盘,所以子问题2的值恒等于AB(1),即值为1;
子问题3实际上是AB(N-1)的问题;
子问题4也是值恒为1;
子问题5实际上也是AC(N-1)的问题;
所以AC(N)=AC(N-1)+1+AB(N-1)+1+AC(N-1)
简化一下,AC(N)=2AC(N-1)+AB(N-1)+2
可结合下图理解:
总结
综上所述,我们可以获得AB(1)=1,AC(1)=2,AB(N)=2AC(N-1)+1,AC(N)=2AC(N-1)+AB(N-1)+2进行运算。
输入N时,可通过上述条件求出AB(N)的值和AC(N)的值。
golang实现方式可参考下面代码片段:
package main import ( "fmt" ) func main() { var n int fmt.Scanf("%d", &n) AB := 1 AC := 2 for i := 2; i <= n; i++ { ab := AB ac := AC AB = (2*ac + 1) % 1000000007 AC = (2*ac + ab + 2) % 1000000007 } fmt.Print(AB, " ", AC) }