汉诺塔相关介绍及计算

汉诺塔的相关介绍及分析

简介

前两天无意中提到了汉诺塔就重新刷了一下相关的题目,感觉有些题目有很多巧妙之处,提到汉诺塔首先想到的是:它是一个递归的经典例题或者是算法入门的例题,其实汉诺塔里更多的是数学思维。

经典汉诺塔

在这里插入图片描述

经典汉诺塔规则: 将A柱子上的圆盘移到C柱子,并且在任何情况下小盘子不能放到大盘子下面。

递归算法求汉诺塔移动方案:

介绍: 要想从某柱子移动一个盘子,首先需要将该盘子上方的所有盘子移动到其他柱子上。设A柱子上盘子数目为n,当n为1时,自然只需要移动一步,即直接将盘中从A柱子移动到C柱子即可;当n不为1时,要将A柱子上的n个盘子移动到C盘子上,首先应该将A柱子中前n - 1个盘子移动到B柱子(借助C柱子)上,再将第n个盘子从A柱子移动到C柱子,最后将前n - 1个盘中移动到C柱子(借助A柱子)即可。
代码实现:

#include<iostream>

using namespace std;

void move(char A, char C){
//输出移动过程(从A移动到C)
	cout<<A<<"->"<<C<<endl;
}
void Hanoi(int n, char A, char B, char C)
	if(n == 1){
	//当只有一个盘子时直接将将该盘子移动到C柱子
		move(A, C);
	}else{
		Hanoi(n - 1, A, C, B);
		//先将前n - 1个盘子借助C柱子,从A柱子移动到B柱子上
		move(A, C);
		//再将第n个盘子从A柱子移动到B柱子上
		Hanoi(n - 1, B, A, C);
		//最后将B柱子上的n - 1 个盘子移动到C柱子上
	}
}
int main(){
	int n;
	char A, B, C;
	cin>>n>>A>>B>>C;//输入盘子数目和各个柱子的编号
	Hanoi(n, A, B, C);
}

优点: 能够直观的观察到每一步的移动情况
缺点: 由于要进行多次递归,所以在盘子数目较大时空间压力很大。并且在多次查找的情况下,每次输入都需要进行递归,时间上也不太可观。

求最小移动次数

求最小移动次数常见的是两种问题——求n个盘子全部从A柱子移动到C柱子的最小移动次数、求n个盘子中第k个盘子移动的次数。

求n个盘子全部从A柱子移动到柱子的最小移动次数:
求移动次数的问题用递归是很不明智的,因为他的移动次数是有规律可循的——在只有一个盘子的情况下移动次数为1;两个盘子时要先将前1个盘子移到B柱子,再将第二个盘子移到C柱子;三个盘子时先将前两个盘子移到B柱子,再将第三个盘子移动到C柱子,最后将前两个盘子移动到C柱子上;以此类推,当盘子数为n时,要先将前n-1个盘子移动到B柱子上,再将第n个盘子移动到C柱子上,最后将前n-1个盘子移动到C柱子上。因为在每个过程中,第n个盘子都只移动了一次,而前n-1个盘子形成的整体移动了两次,相当于将n-1个盘子移动到目标位置的次数乘以二,由此得到递推公式:f(1) = 1, f(n) = 2 * f(n - 1) + 1;

求n个盘子中第k个盘子移动的次数:
很显然第n个盘子移动的次数是1次,前n - 1个盘子要先移动到B柱子再移动到C柱子,所以第n-1个盘子要移动2次,并且在这个过程中第n-2个盘子要移动4次……,以此类推第k个盘子的移动次数是2^(n - k)。

例题:

杭电OJ-1995 汉诺塔 V

AC代码:

#include<iostream>
#include<cmath>

using namespace std;
int main(){
	int t, n, k;
	cin >> k;
	while(t--){
		cin >> n >> k;
		__int64 ans = pow(2, n - k);
		cout<<ans<<endl;
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾醒(AiXing-w)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值