汉诺塔(从电脑递归的思路讲解)

汉诺塔

题意:

大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

起初:

目标:

在这里插入图片描述

思路:

看该题解需要对汉诺塔有个初步思路了解

如果完全没有了解建议先看篇视频了解思路再看模拟电脑递归的过程

https://www.bilibili.com/video/BV1Zh411y7XB/?spm_id_from=333.337.search-card.all.click

汉诺塔本身是一个递归过程,而他递归的思路便是讲n块分解为n-1块思路,继而将n-1快分解为n-2块,直到分解为1块,应用这种思想(假设n=4),我们就不难把前三块放在一个柱子上

在这里插入图片描述

看到上面这个③,也不难想到前面肯定还有第②步,那么问题就变成了如何将三块给拆分为2块的问题了

在这里插入图片描述

到了②就不难发现,想要变成③,需要将3移动到B,然后1移动到A,2移动到B,1再移动到B

可是思路简单,难点在哪?

函数递归,短短几行代码如何去理解就成为了这道题的难点

来,让我们用电脑的思维去解这一个题,先往后看看代码块,结合代码来理解函数递归

1、先进入函数H(4,A,B,C)
2、进入n=4一次调用递归H(3,A,C,B)
3、进入n=3一次调用递归H(2,A,B,C)
4、进入n=2一次调用递归H(1,A,C,B)
5、进行第一次printf(1,A->B) // 此时第四行结束进程
6、进行第二次printf(2,A->C) 
7、进入n=2二次调用递归H(1,B,A,C) // 此时第三行结束进程
8、进行第三次printf(1,B->C) // 此时第7行结束进程

完成了以上的所有之后,②就完成了,现在的状态是

在这里插入图片描述

9、进行第四次printf(3,A->B) 
10、进入n=3二次调用递归H(2,C,A,B) // 此时第2行结束进程
11、进入n=2一次调用递归H(1,C,B,A)
12、进行第五次printf(1,C->A) // 11结束进程
13、进行第六次printf(2,C->B) 
14、进入n=4一次调用递归H(3,A,C,B) // 10结束进程
15、进行第七次printf(2,A->C) 

完成上面之后,③就完成了,现在状态变为

在这里插入图片描述

16、printf(4,A->C)
17、进入n=4二次调用递归H(3,B,A,C) // 此时第二行结束
18、进入n=3一次调用递归H(2,B,C,A) 
19、进入n=2一次调用递归H(1,B,A,C)
20、printf(1,B->C) // 19行结束进程
21、printf(2,B->A)
22、进入n=2二次调用递归H(1,C,B,A) // 18行结束进程
23、printf(1,C->A) // 22行结束进程
24、printf(3,B->C)
25、进入n=3二次调用递归H(2,A,B,C) // 17行结束进程
26、进入n=2一次调用递归H(1,A,C,B)
27、printf(1,A->B) // 26行结束进程
28、printf(2,A->C)
29、进入n=2二次调用递归H(1,B,A,C) // 25行结束进程
30、printf(1,B->C) // 全部进程结束

在这里插入图片描述

附上完整图解
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
其实到这里也不难发现,在变到②的过程中,一共输出了三次,在变到③的过程中,一共输出了七次,在变到④的过程中,一共输出了十五次

也正好对应着的想移动n块,就要 2^n - 1 次

代码块:

C++:

#include <iostream>

using namespace std;

int H(int n, char a, char b, char c)
{
	if(n == 1)
	{
		cout << n << " " << a << "->" << c << endl;
	}
	else 
	{
		H(n - 1, a, c, b); // 第一次调用下一层
		cout << n << " " << a << "->" << c << endl;
		H(n - 1, b, a, c); // 第二次调用下一层
	}
}

int main()
{
	int n;
	cin >> n;
	H(n, 'A', 'B', 'C');
	
	return 0;
}

C

#include <stdio.h>

int H(int n, char a, char b, char c)
{
	if(n == 1)
	{
		printf("%d %c->%c", n, a, c); 
	}
	else 
	{
		H(n - 1, a, c, b); // 第一次调用下一层
		printf("%d %c->%c", n, a, c); 
		H(n - 1, b, a, c); // 第二次调用下一层
	}
}

int main()
{
	int n;
	scanf("%d", &n);
	H(n, 'A', 'B', 'C');
	
	return 0;
}

到这里文章就结束啦,如果有什么疑问及建议欢迎评论区留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值