汉诺塔(蓝桥杯)最简单易懂详细版

直达原题

Description

汉诺塔是一个古老的数学问题:
  有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:每次只能移动一个圆盘;大盘不能叠在小盘上面。
  提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。
问:如何移?最少要移动多少次?

Input

一行,包含2个正整数,一个是N(N<=15),表示要移动的盘子数;一个是M,表示在最少移动d第M步

Output

共2行。
  第一行输出格式为:#No: a->b,表示第M步骤具体移动方法,其中No表示第M步移动的盘子的编号(N个盘子从上到下依次编号为1到n),表示第M步是将No号盘子从a杆移动到b杆(a和b的取值均为{A、B、C})。
  第2行输出一个整数,表示最少移动步数。

Sample Input

3 2

Sample Output

# 2: A->B
7

More Info

时间限制:1.0s 内存限制:256.0MB

分析

汉诺塔的经典做法就是分治法,具体操作就是递归,为什么说是分治法?首先我们需要先明白汉诺塔3层以内的做法,假设柱子是A、B、C;A是起始柱,C是终点柱,按照1、2到n的顺序从上到下命名圆盘。一层的汉诺塔,就是把1从A->C。二层的汉诺塔,先把1移到B,再把2移到C,再把1移到C。对于三层,我们可以这样想:按照前两个的做法,最先进入C柱的一定是最大的盘,所以能把最大的盘从A移动到C做底,就需要前两个盘都在B柱上,现在我们假设已经成功将1,2移动到B,3移动到C,因为C有了最大的盘,所以就不用动C上的3了,此时我们想象3与C融为一体,那么现状就是A上没有盘,B上有两个,那么这时我们把B作为起始柱,C依旧是终点柱,这样就与二层的汉诺塔问题一样了,别忘了我们的前两个盘在B柱上是假设的,实际怎么处理呢,那很简单了,B作为终点柱,一样的移动就完成了。如果是4层的还是如此操作,此时我们总结一下n层的汉诺塔:首先我们需要第n个盘移动到C上,此时B就是n-1个盘的终点柱,这就是n-1层的汉诺塔问题,然后我们需要把B上的n-1层移动到C上,C作为终点柱,这还是n-1层汉诺塔问题,如此递归操作,时间复杂度也是显而易见的为O(2n),最后回到了我们最初的问题:为什么说是分治法,就是把问题分成了两个子问题:
1.把A上n-1个盘移到B,第n个移到C
2.把B上的n-1个移到C

代码实现

# include <bits/stdc++.h>
using namespace std;
int ans=0,n,m;
void hanota(int n,char pos1,char pos2,char pos3)
{
	if(n==1)
	{
		ans++;if(ans==m)cout<<"#"<<n<<":"<<pos1<<"->"<<pos3<<endl;
	}
	else
	{
		hanota(n-1,pos1,pos3,pos2);
		ans++;if(ans==m)cout<<"#"<<n<<":"<<pos1<<"->"<<pos3<<endl;
		hanota(n-1,pos2,pos1,pos3);//或许你会好奇,为什么这句代码下面就不需要ans++了,注意hanota(n-1,pos1,pos3,pos2);里面包含直接从A->C的移动过程所以ans++。这句代码里面只有递归到n==1才ans++
	}

}
int main()
{
	cin>>n>>m;
	hanota(n,'A','B','C');
	cout<<ans<<endl;
	return 0;
}
posted @ 2023-07-30 01:37  LongDz  阅读(294)  评论(0)    收藏  举报