汉诺塔变种(邻近柱子才可移动)
原题网址:http://acm.hdu.edu.cn/showproblem.php?pid=2064
汉诺塔问题是典型的递归问题,解决递归问题的两个核心条件是:
- 原始问题转化为规模更小的子问题
- 找到递归出口(结束更深层次递归的条件)
原始的汉诺塔问题要求一共三根杆,将最左边的杆上的圆盘全部转移到最右边的杆子上,其它基本限制不过多赘述。
该汉诺塔变种要求盘子只能在相邻的柱子之间移动,而不能直接从第一个柱子移动盘子到第三个柱子上,或从第三个柱子上直接移动到第二个柱子上。要求移动的最少次数。
子问题转化
该变种的子问题转化思路如下:
假设将n个盘子从第一个柱子转移到第三个柱子所需要的移动总次数是f(n)。将现有的n个盘子看做两个部分,最下面的大盘子为一部分,大盘子上面的n-1个盘子为一部分,先将大盘子上的n-1个盘子移动到第三个柱子(这里已经出现了原问题的子问题了,这个过程的移动次数和单纯的将第一个柱子上的n-1个盘子移动到第三个柱子,即f(n-1)是等价的),这一步的移动次数是f(n-1);之后将最下面的大盘子从第一个柱子移动到第二个柱子,移动一次;接下来将第三个柱子上的n-1个柱子从第三个柱子上移动到第一个柱子上,这里又是一个f(n-1);之后将第二个柱子上的大盘子移动到第三个柱子上,移动一次;最后将第一个柱子上的n-1个盘子移动到第三个柱子上,又是一个f(n-1)。至此,从最表层看,任务已经完成了。最终可以得到一个递推公式如下:
f
(
n
)
=
3
f
(
n
−
1
)
+
2
f\left( n \right) =3f\left( n-1 \right) +2
f(n)=3f(n−1)+2
递归出口
递归到最深处,当n=1,就只需要两步,即f(1)=2。
代码
#include <iostream>
using namespace std;
long long Hanoi(int n){
if(n==1){
return 2;
}
else
return 3*Hanoi(n-1)+2;
}
int main() {
int n;
while(scanf("%d",&n)!=EOF){
cout<<Hanoi(n)<<"\n";
}
}