首先,让我们来看一下汉诺塔问题,同兔子数列一样,这里也有个故事(谢谢bing):
在世界中心贝勒纳斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
真是一个可怕的故事呢,然而让我们看看这个计算的数量级,在n=64的时候,我们假设1秒移动一个金片,而且全部是最优情况,我们一共要移动18446744073709551615次,也就是18446744073709551615秒,也就是584,942,417,355年,已经达到了可怕的10^12级别。
好了不多说了,让我们回到coding和数学的角度来看这个经典的问题,我们采用划归的思想:
1.假设我们有一个圆盘和三根柱子,直接a->c就行了对吧
2.现在我们有两个圆盘和三根柱子,那就是a->1->c;a->2->b;c->1->b就行了
3.现在我们升至三个,也就是a->1->b;a->2->c;b->1->c;a->3->b;c->1->a;c->2->b;a->1->b也就可以了。
然后让我们普及到n个,不难发现其为2^n-1;如此大量的计算,我们就一定要用代码来实现了,下面请看。
递归递推
毫无疑问,本思想是解决这个问题最好或最简单的思想,因为其完美的满足了递归递推的要点:1.有边界 2.有表达式,结合以上论述,我们可以把n-1个盘子视为一个整体,第n个为一个部分,依次递归就行,代码:
#include<bits/stdc++.h>
using namespace std;
int go(int n,char a,char b)
{
cout << a << "->" << n << "->" << b << endl;;
}
int hanoi(int n,char a,char b,char c)
{
if(n == 1)
go(1,a,b);
else
{
hanoi(n - 1,a,c,b);
go(n,a,b);
hanoi(n - 1,c,b,a);
}
}
int main ()
{
int n;
char a,b,c;
cin >> n >> a >> b >> c;
hanoi(n,a,b,c);
return 0;
}
当然了,我也曾经见到过另一种递归算法的表达,整体大同小异,我凭记忆推了出来:
#include<bits/stdc++.h>
using namespace std;
void move(char x, char y, int* all)
{
cout << x << "->" << y << "\n";
all += 1;
}
void hanoi(int num, char a, char b, char c, int *all)
{
if (num == 1)
{
move(a, c, all);
}
else
{
hanoi(num - 1, a, c, b, all);
move(a, c, all);
hanoi(num - 1, b, a, c, all);
}
}
int main()
{
int n, sum = 0;
cin >> n;
hanoi(n, 'A', 'B', 'C', &sum);
cout << sum <<endl;
return 0;
}
就我目前的知识而言,我认为构造一个二叉树Hanoi然后进行中序遍历也是可以的,但是代码水平有限,所以还不会写,根据他人评价,这样的意义不大,因为辅助空间太多。
1万+




被折叠的 条评论
为什么被折叠?



