汉诺塔问题描述:
汉诺塔是根据一个传说形成的数学问题,有三根杆子A,B,C。A杆上有 n 个 (n>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
(1)每次只能移动一个圆盘;
(2)大盘不能叠在小盘上面。
提示:可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
编程解决两个问题:
- 当有n个盘子时,需要移动多少次才能完成。
- 打印每次移动的过程。
分析:
第一个问题:
假设A杆上的n个盘子以B杆为临时杆,移动到C杆,需要移动的次数记为f(n),分解为以下三步:
第一步,将A杆上面的(n - 1)
个盘子以C杆为临时杆,移动到B杆,则次数为f(n - 1)
;
第二步,将A杆上剩余的最大的盘子从A杆直接移动到C杆,次数为1
;
第三步,将B杆上面的(n - 1)
个盘子以A杆为临时杆,移动到C杆,则次数为f(n - 1)
。
则有 f(n) = f(n - 1) + 1 + f(n - 1) = 2 * f(n - 1) + 1
由高中的等比数列知识可知:f(n) = 2^n - 1
边界条件:f(1) = 1
第二个问题:
设A杆用begin
表示,B杆用middle
表示,C杆用end
表示,分解为三步:
hanoi(n - 1, begin, end, middle);
System.out.println(begin + " --> " + end);
hanoi(n - 1, middle, begin, end);
代码:
public class Hanoi {
public static void main(String[] args) {
int n = 5;
System.out.println(f(n));
hanoi(n, 'A', 'B', 'C');
}
// 解决第一个问题
public static int f(int n) {
if (n == 1) return 1;
return 2 * f(n - 1) + 1;
}
// 解决第二个问题
public static void hanoi(int n, char begin, char middle, char end) {
if (n == 1) {
System.out.println(begin + " --> " + end);
return ; // 必须要有返回,结束递归
}
hanoi(n - 1, begin, end, middle);
System.out.println(begin + " --> " + end);
hanoi(n - 1, middle, begin, end);
}
}
可以使用递归的问题:
- 大问题可以分解成子问题
- 子问题的解决方法和大问题一模一样,只是问题规模不同
- 有终止条件
使用递归需要注意的问题:
- 警惕重复计算问题
- StackOverflowError
结束语:如果本篇博客对您有帮助,请点赞、收藏或关注,您的鼓励是博主进步的动力,感谢支持,共同进步。