汉诺塔之谜(递归和递推)(超级超级容易理解)

汉诺塔问题是很典型的递归问题,非常符合大事化小,大问题拆解为子问题,那么废话不多说,让我们看看这到底是个啥难题。

【题目描述】

约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*/

希望可以帮助到你啦

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值