题目
首先我们来看一下题目
汉诺塔问题,条件如下:
1、这里有A、B、C和D四座塔。
2、这里有n个圆盘,n的数量是恒定的。
3、每个圆盘的尺寸都不相同。
4、所有的圆盘在开始时都堆叠在塔A上,且圆盘尺寸从塔顶到塔底逐渐增大。
5、我们需要将所有的圆盘都从塔A转移到塔D上。
6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。
请你求出将所有圆盘从塔A移动到塔D,所需的最小移动次数是多少。
输入格式:
任意多行,每行包含一个整数n。1≤n≤12
输出格式:
对每一行输入,在对应一行中输出一个满足条件的最小移动次数的值。
输入样例:
1 3
输出样例:
1 5
分析
我们之前探讨过正常的汉诺塔问题(三个),详细看我的第一篇博客。
三个汉诺塔时用到了函数的递归方法
对于n个圆盘,将它们从塔A动到塔C,可以分解为以下步骤:
- 将n-1个圆盘从塔A移动到塔B;
- 将第n个最大的圆盘从塔A动到塔C;
- 将n-1个圆盘从塔B移动到塔。
而四阶的会比三阶的更加复杂,因为多了更多的选项
还是让我们从少的开始慢慢向后推进
当只有一个时候,明显是1
当只有两个时候,明显是3 前两个的值和三阶汉诺塔是相同的
但是到三个时候,变成了5 而三阶汉诺塔是7 ,从这开始出现差别
当到第四个时候,我又想起了类似于三阶汉诺塔的方法,将一部分看成一个整体去进行计算,将第一个和第二个看成一个整体去进行移动,
所以此时就是 (假设令求汉诺塔次数的函数为f4()),2*f4(2) +3;
所以就产生递归为f(x) = 2*f4(2) + 3 但是此时得出的结果是
但是实际的结果是
发现从第六个开始就不正确,并且看不出来从 6之后有任何的规律
这是为什么呢,因为上述的计算其实是f4(x-2) + f3(2)(f3()为三阶汉诺塔的移动次数)
其实可以看出,四阶汉诺塔可以看成
层数较少的四阶汉诺塔和三阶汉诺塔的组合
什么意思呢
举个六层的例子
假设先将上面三层看成一个整体,进行移动到B/C柱,然后将剩余的三个大的移动到D上,又因为上面三个占住了一个柱子,所以移动剩余三个柱子就变成了三阶汉诺塔的问题,最后再将上方是哪个移动到D上
所以依次类推四阶汉诺塔步骤为
1.首先 将n-k个盘子移动到B或C柱
2. 然后将k个盘子移动到D柱(这个步骤是三汉诺塔问题)
3. 最后将最开始移动的n-k个盘子移动到D柱
所以就是 f4(x) = 2 * f4(n - k) + f3(k) 又因为要求最小值,所以就要进行比较,k取何值时取得最少的步骤。
所以总体思路已经明确了,下面进行代码实现
代码实现
#include <stdio.h>
int main()
{
int f4[100] = { 0 };//用来存放三阶汉诺塔的移动次数
int f3[100] = { 0 };//用来存放三阶汉诺塔的移动次数
f3[1] = 1;
int num = 0;
scanf("%d", &num);
//计算三阶汉诺塔
for (int i = 2; i <= num; i++)
{
f3[i] = 2 * f3[i - 1] + 1;
}
//计算四阶汉诺塔
memset(f4, 0x3f, sizeof(f4));//将其中的值变成很大的数,方便后续进行最小值的比较
f4[0] = 0;
for (int n = 1; n <= num; n++)
{
for (int k = 0; k <= n; k++)
{
f4[n] = (f4[n] < (2 * f4[n - k] + f3[k])) ? f4[n] : (2 * f4[n - k] + f3[k]);
}
}
printf("%d", f4[num]);
return 0;
}