蓝桥杯——汉诺塔问题
一、汉诺塔问题描述
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
规则:
1.三个柱子A,B,C,需要将A柱子上的n个圆盘借助B柱子移动到C盘上
2.一次只能移动一个圆盘
3.移动过程中,小圆盘不能在大圆盘的下面
二、用到的函数
1.将圆盘从一个柱子移动到另一个柱子,计算移动的次数
void move(char a,int n,char b)
{
num++;
}
2.运用递归函数解决汉诺塔问题
void hanoi(int n,char x,char y,char z)
{
if(n==1) move(x,1,z);//此时x柱子上面只有一个圆盘,将编号为1的圆盘 从x柱子 移动到z柱子
else{
hanoi(n-1,x,z,y);//将x柱子上的 n-1个圆盘移动到y柱子上,此时z柱子作为辅助
move(x,n,z);//将编号为n的圆盘 从x柱子 移动到z柱子
hanoi(n-1,y,x,z);//将y柱子上的 n-1个圆盘移动到z柱子上,此时x柱子作为辅助
}
}
/*
//其中,src代表原来的柱子
//tmp代表辅助柱子
//des代表目的柱子
//参数的顺序是 :(要移动的柱子、原柱子、辅助柱子、目的柱子)
void hanoi(int n,int src,int tmp,int des)
{
if(n==1) move(src,1,des);
else{
hanoi(n-1,src,des,tmp);//将n-1个柱子从src移动到tmp上
move(src,n,des);
hanoi(n-1,tmp,src,des);//将tmp上的n-1个柱子移动到des上
}
}
*/
三、汉诺塔问题的移动次数
递归函数表达:f(n)=f(n-1)+f(n-1)+1 f(1)=1
利用数学归纳法可以得到总的移动次数为:2的n次方减1
四、如果将课本上的Hanoi塔问题稍做修改:仍然是给定N只盘子,3根柱子,但是允许每次最多移动相邻的M只盘子(当然移动盘子的数目也可以小于M),最少需要多少次?
例如N=5,M=2时,可以分别将最小的2个盘子、中间的2个盘子以及最大的一个盘子分别看作一个整体,这样可以转变为N=3,M=1的情况,共需要移动7次。
现在每次可以一次性挪动M个盘子,则按照题目的提示,N个盘子一个可以打包成个“大盘子”,于是题目要求的值就是2的N/M次方减1.
算法如下:
1 #include<iostream>
2 using namespace std;
3 int num=0;
4 void move(char a,int n,char b)
5 {
6 num++;
7 }
8 void hanoi(int n,char x,char y,char z)
9 {
10 if(n==1) move(x,1,z);
11 else{
12 hanoi(n-1,x,z,y);
13 move(x,n,z);
14 hanoi(n-1,y,x,z);
15 }
16 }
17 int main()
18 {
19 int n,m;
20 cin>>n>>m;
21 if(n%m==0) n=n/m;
22 else{
23 n=n/m;
24 n++;
25 }//判断是否整除来确定最终的圆盘个数
26 hanoi(n,'A','B','C');
27 cout<<num<<endl;
28 return 0;
29 }