今天为大家讲一道非常有趣的问题,hanoi塔问题,相信很多同学都曾经玩过这个游戏,今天我们尝试着靠编程来解决它
题目描述
A、B、C 是3个塔座。开始时,在塔座A 上有一叠共n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动1个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至A,B,C 中任一塔座上。
试设计一个算法,用最少的移动次数将塔座A 上的n个圆盘移到塔座B 上,并仍按同样顺序叠置。
编程任务:
对于给定的正整数n,编程计算最优移动方案。
规则(1):每次只能移动1个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至A,B,C 中任一塔座上。
试设计一个算法,用最少的移动次数将塔座A 上的n个圆盘移到塔座B 上,并仍按同样顺序叠置。
编程任务:
对于给定的正整数n,编程计算最优移动方案。
输入
输入由多组测试数据组成。每组测试数据的第1 行是给定的正整数n。
输出
对应每组输入,输出的每一行由一个正整数k和2 个字符c1 和c2 组成,表示将第k 个圆盘从塔座c1 移到塔座c2 上。
样例输入 Copy
3
样例输出 Copy
1 A B 2 A C 1 B C 3 A B 1 C A 2 C B 1 A B
提示
考察一个普通的汉诺塔问题,如果按照最少步骤移动(即没有无意义的移来移去):
普通的汉诺塔(把盘子1~k由source移动到target)问题分三个阶段
1.把盘子1~k-1由source(k上面)移动到assistant
2.把盘子k由source移动到target
3.把盘子1~k-1由assistant移动到target(k上面)
在这里我们把盘子1~k-1的移动看做一个整体进行移动
那么假设存在一个违反双色规则移动的盘子m-1,它放在了盘子m+1上,但是你让盘子m怎么办呢?在移动1~m+1这个层次并没有盘子m在m+1所在柱子之外的两个柱子间移动的步骤。
m-1放在m+3、m+5、m+7……之上也是不可能的,因为同样地,就拿m+3来说,在移动1~m+3这个层次没有盘子m+2在m+3所在柱子之外的两个柱子间移动的步骤。
所以这种违规必然是一个多余的操作,违规地移动之后,必须要移下来才能正常继续。
普通的汉诺塔(把盘子1~k由source移动到target)问题分三个阶段
1.把盘子1~k-1由source(k上面)移动到assistant
2.把盘子k由source移动到target
3.把盘子1~k-1由assistant移动到target(k上面)
在这里我们把盘子1~k-1的移动看做一个整体进行移动
那么假设存在一个违反双色规则移动的盘子m-1,它放在了盘子m+1上,但是你让盘子m怎么办呢?在移动1~m+1这个层次并没有盘子m在m+1所在柱子之外的两个柱子间移动的步骤。
m-1放在m+3、m+5、m+7……之上也是不可能的,因为同样地,就拿m+3来说,在移动1~m+3这个层次没有盘子m+2在m+3所在柱子之外的两个柱子间移动的步骤。
所以这种违规必然是一个多余的操作,违规地移动之后,必须要移下来才能正常继续。
题解代码:
#include<iostream>
#include<string>
using namespace std;
int n;
void hanoi(int k,char from,char assistant,char to){
if(k==1){
printf("%d %c %c ",1,from,to);
return ;
}
else{
hanoi(k-1,from,to,assistant);
printf("%d %c %c ",k,from,to);
hanoi(k-1,assistant,from,to);
}
}
int main(){
scanf("%d",&n);
hanoi(n,'A','C','B');
return 0;
}
#include<string>
using namespace std;
int n;
void hanoi(int k,char from,char assistant,char to){
if(k==1){
printf("%d %c %c ",1,from,to);
return ;
}
else{
hanoi(k-1,from,to,assistant);
printf("%d %c %c ",k,from,to);
hanoi(k-1,assistant,from,to);
}
}
int main(){
scanf("%d",&n);
hanoi(n,'A','C','B');
return 0;
}
题解思路:
这道题的思路我们通过第一次递归hanoi(n,A,C,B)来讲解,在将A底下最大的n的移到目的B柱之前,需要先将A柱上的1到n-1个环通过B移到C上,
我们可以利用第二次递归hanoi(n-1,A,B,C)来运算;在将A底下最大的n的移到目的B柱之后,我们便要将C上的1到n-1个环通过A柱移到B柱上,利用递归
hanoi(n-1,C,A,B)实现,每次递归只能移一个,搞清楚起始柱from,中间柱(协助作用)assistant和目的柱to的关系,即将最大的n由from移到to之前,需要将1到
n-1移到assistant上;移完后需将assistant的1到n-1再通过from移到to上来