第二周我们开始解决一些经典的递归问题
- 题目链接:【经典】汉诺塔问题 - 题目 - 青藤 OJ
- 题目来源:经典题目
题目大意
非常经典的汉诺塔问题。
这题要求输入
,表示 A 柱子上有 n 个圆盘。现在需要移动到 C 柱子上,要求输出方案总数与方案。
输入:
3
输出:
7
Move A to C
Move A to B
Move C to B
Move A to C
Move B to A
Move B to C
Move A to C
解法
首先汉诺塔问题大家应该非常熟悉了。
数量上来说
即
所以
是公比为 2 的等比数列,首项为
,所以
所以第一个小问题就很容易解决了
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
//<< 在位运算里面是左移,不熟悉的话可以for循环求2^n
printf("%dn",(1<<n)-1);
//输出把 n 个盘子从 'A' 借助 'B' 移到 'C' 的解决方案
hanoi(n,'A','B','C');
return 0;
}
现在我们的关键就是怎么解决这个 hanoi(n,'A','B','C');
做递归类问题的核心就两点:
- 边界情况特别处理
- 假装这个函数的功能已经完成了,用这个函数实现这个函数(用魔法打败魔法)
按照这两个思路,我们可以写出下面的标程
#include <bits/stdc++.h>
using namespace std;
void hanoi(int n, char x, char y, char z) {
//要把 n 个盘子从 x 通过 y 移到 z
//边界情况
if (n == 1) {
//直接从 x 移到 z
printf("Move %c to %cn", x, z);
return;
}
//先把 n-1 个从 x 移到 y
hanoi(n - 1, x, z, y);
//把第 n 个从 x 直接移到 z
printf("Move %c to %cn", x, z);
//再把那 n-1 个从 y 移到 z
hanoi(n - 1, y, x, z);
}
int main() {
int n;
scanf("%d", &n);
//<< 在位运算里面是左移,不熟悉的话可以for循环求2^n
printf("%dn", (1 << n) - 1);
//把 n 个盘子从 'A' 借助 'B' 移到 'C'
hanoi(n, 'A', 'B', 'C');
return 0;
}
去掉注释,其实很短
#include <bits/stdc++.h>
using namespace std;
void hanoi(int n, char x, char y, char z) {
if (n == 1) {
printf("Move %c to %cn", x, z);
return;
}
hanoi(n - 1, x, z, y);
printf("Move %c to %cn", x, z);
hanoi(n - 1, y, x, z);
}
int main() {
int n;
scanf("%d", &n);
printf("%dn", (1 << n) - 1);
hanoi(n, 'A', 'B', 'C');
return 0;
}
用递归的方法写程序就是这么简单、巧妙、且短小精悍。