Hanoi双塔问题(汉若塔问题)
这两个题目非常的像,一个是双塔,一个是单塔。
一.汉若单塔(也称经典汉若塔问题)
首先,我们先画个 n=3 图:
要把 A 柱上的“圆盘”移到 C 柱上,要求无论在哪个柱子上的圆盘都是大的在下面,小的在上面。求从 A 柱上的圆盘移到 B 柱上要多少步?
1. 实践
遇到这种问题,首先想到的是先模拟一次,如下图:
怎么样?看完过程,是不是清晰了许多?全过程是这样的:
步数 | 操作 |
---|---|
1 | ① A to C |
2 | ② A to B |
3 | ① C to B |
4 | ③ A to C |
5 | ① B to A |
6 | ② B to C |
7 | ① A to C |
2. 探索
总共7步。仔细观察我们可以发现,移动的盘子是对称的,如上表:①②①③①②①。以③为点,左右对称。再看看右边①②①,也是对称的,这是 n=2 时移动的步数。我们是不是可以推测出如果 n=4 时,①②①③①②①④①②①③①②①是移动顺序呢?事实证明的确如此。移动顺序总是上一个序列加上新的盘子再加上一个序列。
由此可得递推公式:
f
i
=
f
i
−
1
∗
2
+
1
(
i
≤
n
)
f_i=f_{i-1}*2+1(i \le n)
fi=fi−1∗2+1(i≤n)
3. 运用
如何运用到c++里面呢?
int n=0;
scanf ("%d", &n);
int f[10010]={0};
for (int i = 1 ; i <= n ; ++i)
f[i] = f[i-1] * 2 + 1;
printf ("%d\n", f[n]);
这就是主程序。
4. 思考
如何输出中间的步骤?可在评论区回答 or 讨论!
二.汉若双塔
1. 认识
我们来看看汗若双塔长什么样子吧:
他就是每种型号多了1个盘子。移动起来的步骤也就乘2了。
2. 实现
int n=0;
scanf ("%d", &n);
int f[10010]={0};
for (int i = 1 ; i <= n ; ++i)
f[i] = f[i-1] * 2 + 1;
printf ("%d\n", f[n] * 2);
三.加强
当数据 n<=200 时,我们应该怎么做? answer :当然是 无符号 long long 啦。
NO!NO!NO!我们应该开高精度,这才是正解!!!
康康 code :
int n;
int ans[210];
int j;
for(int i=1;i<=n;i++)
{
for(j=1;j<=200;j++)
ans[j]=ans[j]*2;
ans[1]++;
for(j=1;j<=200;j++)
if(ans[j]>=10)
{
ans[j+1]+=ans[j]/10;
ans[j]=ans[j]%10;
}
}
for(j=1;j<=200;j++)
ans[j]=ans[j]*2;
for(j=1;j<=200;j++)
if(ans[j]>=10)
{
ans[j+1]+=ans[j]/10;
ans[j]=ans[j]%10;
}
bool p=0;
for(int i=200;i>=1;i--)
{
if(ans[i]!=0)
p=1;
if(p)
printf("%d",ans[i]);
}