什么是汉诺塔问题
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?(每次只能移动1个盘子,大盘子只能放在小盘子下面)
这里还有一个预言: 当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽,也就是世界毁灭。
想要把64片金片从一根针上全部需要多长时间呢?也就是说世界毁灭会多长时间呢?让我们往下看
汉诺塔问题的实现
简单汉诺塔的推理
一个盘子
当只有一个盘子的时候,很直接的看出,只需移动一次
两个盘子
有两个盘子时,就需要借助第三个柱子才能实现
第一步:
第二步:
第三步:
最终:
如图,最终需要三步
三个盘子
第一步和第二步:
第三步:
第四步:
第五步:
第六步,第七步:
所以如图,三个盘子需要移动7次
汉诺塔问题的实现
偏数学方式的实现
以三个盘子为例:
先把三个盘子想象成一个盘加两个盘子(并且把这两个盘子看成整体)
先把这个整体移动到B柱上:
在把A柱上的那一个盘子移动到C主上
最后,再将两个盘子整体移动到C上
所以从始至终,一个盘和那两个盘子的整体只移动了三次,其中独自的那个盘子从A到C移动两次,两个盘子的整体移动了两次
可以看出,两个盘子每次整体的移动都是一个含有两个盘子的汉诺塔问题
所以,假设n是圆盘的数量,T(n)是移动n个圆盘的移动次数。
当n=1时,T(1)=1
当n=2时,T(2)=2T(1)+1
当n=3时,T(3)=2T(2)+1
……
就可以得出:
也很容易得到公式: f(n) = 2^n-1
代码的实现:
int Hanoi(int n) { if (n == 1) { return 1; } else { return 2*Hanoi(n - 1) + 1; } } int main() { int n = 0; printf("输入A塔中盘子个数"); scanf("%d", &n); printf("总共挪动的次数为:%d\n", Hanoi(n)); return 0; }
结果:
偏过程方式的实现
从含有两个盘子的汉诺塔中可以看出来:
1号盘是借助于B柱,才最终到达A柱2号盘直接从A柱到C柱
再分析一下含有三个盘子的汉诺塔:
1号整体是借助柱到达B柱,
2号盘直接从A柱到C柱,
最终把整体借助A移动到C上
其中对于1号整体的移动就是含有两个盘的汉诺塔问题>所以,以此类推,n个盘的汉诺塔,它的从上到下前n-1个盘是通过C柱到达B柱,最下面的一个盘是由A直接到C,最后再把整体借助A柱移动到C柱
代码实现:
void move(char x,char y) { printf("从 %c 移动到 %c\n", x, y); } void Hanoi2(int n, char A, char B, char C) { if (n == 1) //只有一个盘子 { ShowMove(A, C); //直接移动即可 } else { Hanoi2(n - 1, A, C, B); //将上边n-1个盘子从a上借助c到达b ShowMove(A, C); Hanoi2(n - 1, B,A,C); //将上边n-1个盘子从b上借助a到达c } } int main() { int n = 0; printf("输入A塔中盘子个数"); scanf("%d", &n); Hanoi2(n, 'A', 'B', 'C'); return 0; }
代码解读:
move(char,char)函数是为了从A柱上把最下面的盘子移动到C柱
void Hanoi2(int n, char a, char b, char c)中,形参n是盘子个数,a,b,c表示盘子在a上,借助b,最终到达c
结果:
全部代码:
#include <stdio.h> int Hanoi(int n) { if (n == 1) { return 1; } else { return 2*Hanoi(n - 1) + 1; } } void ShowMove(char x,char y) { printf("从 %c 移动到 %c\n", x, y); } void Hanoi2(int n, char a, char b, char c) { if (n == 1) { ShowMove(a, c); } else { Hanoi2(n - 1, a, c, b); ShowMove(a, c); Hanoi2(n - 1, b,a,c); } } int main() { int n = 0; printf("输入A塔中盘子个数"); scanf("%d", &n); printf("总共挪动的次数为:%d\n", Hanoi(n)); Hanoi2(n, 'A', 'B', 'C'); return 0; }
预言解读
根据前面得到的公式,当n为64时,需要移动2^64-1 = 18446744073709551615次
假如每秒钟一次
18446744073709551615÷31556952=584554049253.855年
移完这些金片需要5845亿年以上
所以到时候世界是否毁灭就不管你我的事啦! ~