汉诺塔问题是很典型的递归问题,非常符合大事化小,大问题拆解为子问题,那么废话不多说,让我们看看这到底是个啥难题。
【题目描述】
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到中间的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。
这是一个著名的问题,几乎所有的教材上都有这个问题。由于条件是一次只能移动一个盘,且不允许大盘放在小盘上面,所以64个盘的移动次数是:18,446,744,073,709,551,615
这是一个天文数字,若每一微秒可能计算(并不输出)一次移动,那么也需要几乎一百万年。我们仅能找出问题的解决方法并解决较小N值时的汉诺塔,但很难用计算机解决64层的汉诺塔。
假定圆盘从小到大编号为1, 2, …
你是不是觉得最大的板很烦,如果能将最大的板移动到第三个柱子上问题就迎刃而解了,其实问题的核心就是将底盘(最大的板移动到指定位置)。
但是你再想想,最大的板其实没有明显的界限,如果将一开始的第三块板移走,那么原有的第二块板就变成了最大的板,这是头疼的问题就又变成了,如何将最大板(原有的中间那块板)移走
如果将第二块板也拿走,就只剩下一块板了,别说你一块板都不会移到第三块板上了哈
这样思考是不是就是一个递归的过程了
所以总结一下:就是将除了最大一块板之外的其余的板全部移动到第二个杆子,再将最大板移动到第三个杆子,最后将其余的板移到第三个杆子
下面直接上代码
先用递推的方法这个不细讲
#include <stdio.h>
int f[20];
int main()
{
int i = 0;
int n = 0;
scanf("%d", &n);
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = 1 + f[i - 1] * 2;
}
printf("%d\n", f[n]);
return 0;
}
我分来分析一下递归
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
static int cnt = 0;
void move(char a[], char c[])
{
printf("%s ---> %s\n", a, c);
cnt++; //每一移动就cnt+1,最后可以看到移动的次数
}
void hanoi(int n, char a[], char b[], char c[])
{
if (n == 1) //如果只有个板
{
move(a, c); //直接将板从 第一个杆子 移动到 第三个杆子
}
else //如果有>=2个板
{
hanoi(n - 1, a, c, b); //将除最大板之外的其余板,从杆子1移到杆子2
move(a, c); //将板从 第一个杆子 移动到 第三个杆子
hanoi(n - 1, b, a, c); //将除最大板之外的其余板,从杆子2移到杆子3
}
}
int main()
{
int num;
scanf("%d", &num); //num表示铜板的数量
char a[] = "杆子1";
char b[] = "杆子2";
char c[] = "杆子3";
hanoi(num, a, b, c);//ABC表示三个杆子
printf("%d", cnt);
return 0;
}
或者可以直接计数,不用显示过程
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
static int cnt = 0;
void move(char a, char c)
{
cnt++; //每一移动就cnt+1,最后可以看到移动的次数
}
void hanoi(int n, char a, char b, char c)
{
if (n == 1) //如果只有个板
{
move(a, c); //直接将板从 第一个杆子 移动到 第三个杆子
}
else //如果有>=2个板
{
hanoi(n - 1, a, c, b); //将除最大板之外的其余板,从杆子1移到杆子2
move(a, c); //将板从 第一个杆子 移动到 第三个杆子
hanoi(n - 1, b, a, c); //将除最大板之外的其余板,从杆子2移到杆子3
}
}
int main()
{
int num;
scanf("%d", &num); //num表示铜板的数量
hanoi(num, 'A', 'B', 'C');//ABC表示三个杆子
printf("%d", cnt);
return 0;
}
/* 作者:zhy 2021-1-21*/