汉诺塔问题

汉诺塔问题(Hanoi Tower Problem)

汉诺塔问题家喻户晓,它源于一个印度的神话,内容如下:

在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

这个问题看起来十分可怕,实际上很简单。接下来就解决一个问题来体会这个小小问题中的大大的递归思想!

有三根柱子,第一根柱子上有n个从下向上越来越小的圆盘。

目标:使第一根柱子上的n个圆盘按原样摆放在另一个柱子上。

注:一次移动一个圆盘,不可以出现大的盘子在小的盘子上面的情况。

解:
首先我们先玩一下这个游戏。

接着我们找出一个规律,要彻底地把这个塔移开,我们必须要移开上方的n-1个盘子,使最下面的盘子可以移动到另一个柱子上,然后在把上方的n-1个盘子移动到最下
面的盘子(也就是最大的盘子)上就可以解决了。而n-1个盘子的移动方法也一样,因为最下面的大盘子对上面的n-1个盘子的移动毫无影响。

因此,我们可以得出一个递推式:

\[F_n=2F_{n-1}+1 \]

\(F_n\)代表第一个柱子上有n个盘子的情况,所以这个问题得到了解决

代码如下:时间复杂度\(O(2^n )\)

#include <iostream>
using namespace std;
int main()
{
	int n;
	int f[20];
	cin>>n;
	f[1]=1;
	for(int i=2;i<=n;i++)
	f[i]=2*f[i-1]+1;
	cout<<f[n]<<endl;
	return 0; 
}

这个问题就简单地这么解决了。(瞎说,还有更简单的方法)

让我们来看一看输出结果:从n=1开始:1 3 7 15 31 63 127 255 511 1023 2047 4095 8191……

我们发现一个规律,所有的\(F_n\)满足:

\[F_n=2^n-1 \]

这才是最简单的方法!

有些人会说,这个方法是瞎猜的,只是凭运气而已,没事儿,我可以证明一下。

证:
数学归纳法。
当n=1时,F(n)=1,2n-1=1;命题显然成立
假设n=k时命题成立,即F(k)=2k-1;
当n=k+1时,F(k+1)=F(k)*2+1;
因为F(k)=\(2^k\)-1
所以
\(F(k+1)\)
\(=2F(k)+1\)
\(=(2^k-1)*2+1\)
\(=2^{k+1}-1\)
证毕。
所以这才是这种汉诺塔问题的最优解!

最终代码如下:时间复杂度O(⁡\(log_2n\) )

#include <iostream>
using namespace std;
int qp(int a,int b)
{
	if(b==0)
	return 1;
	int t=qp(a,b/2);
	if(b%2==0)
	return t*t;
	else
	return t*t*a;
}
int main()
{
	int n;
	cin>>n;
	cout<<qp(2,n)-1<<endl;
	return 0;
}
posted @ 2019-07-26 12:37  wweiyi  阅读(341)  评论(1编辑  收藏  举报
js脚本