相邻移动汉诺塔(hdoj-2064):
现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。现在有N个圆盘,至少多少次移动才能把这些圆盘从最左边移到最右边?
这个题目和之前的汉诺塔问题相比最大的区别就是无法直接实现将圆盘直接从A柱移动至C柱,而是需要从A柱移动至B柱,再从B柱移动至C柱。那么我们需要重新考虑移动方式,我们可以从N=1、2的三个简单情况开始考虑:
当N=1时,移动步骤为A→B,B→C。
当N=2时,移动步骤为A→B,B→C,A→B,C→B,B→A,B→C,A→B,B→C。(此时可以认为将第二片移动至B,再将第二片移动至C。)
由此我们可以把移动步骤抽象为:
1)将A柱上的N-1个圆盘移动至C柱(即F1(N-1)步)。
2)将A柱上的第N个圆盘移动至B柱(即1步)。
3)将C柱上的N-1个圆盘移动至A柱(即F1(N-1)步)。
4)将B柱上的第N个圆盘移动至C柱(即1步)。
5)将A柱上的N-1个圆盘移动至C柱(即F1(N-1)步)。
可以得到递归公式为F1(N)=3*F1(N-1)+2,由此编写函数实现如下:
unsigned long long int hanoi(int n)
{
long long int ct;
if (n == 1)
ct = 2;
else
{
ct = 3 * hanoi(n - 1) + 2;
}
return ct;
}
可叠相邻移动汉诺塔(hdoj-2064):
具体题目与上述题目相似,区别在于我们允许最大的盘子放到最上面(只允许最大的放在最上面),现在有N个圆盘,至少多少次移动才能把这些圆盘从最左边移到最右边?
在起初考虑这个问题的时候,我认为其移动步骤为:
1)将A柱上的N-1个圆盘移动至B柱(即F2(N-1)步)。
2)将A柱上的第N个圆盘移动至B柱(即1步)。
3)将B柱上的第N个圆盘移动至C柱(即1步)。
4)将B柱上的N-1个圆盘移动至C柱(即F2(N-1)步)。
此时可得到递归公式为F2(N)=2*F2(N-1)+2,但是所得结果与正确结果不符合。问题出在哪里呢?
这个移动步骤的问题在于:每次递归过程中,均会把该递归过程中的最大盘子视为总体的最大盘子进行操作,也就是会把局部的最大盘子放在最上方。这个步骤和实际题目要求的只允许整体的最大盘子放在上面不符,减少了很多需要移动的步骤。
实际,我们通过对N=1、2、3等情况模拟,可以发现实际的操作步骤应该与上一题的操作步骤相同,只是在最后一步的时候,将N-1个圆盘移动至B柱,然后将第N个圆盘移动至B柱,然后将第N个圆盘移动至C柱,最后将N-1个圆盘移动至C柱。也就是只在递归的最上层改变递归过程,递归的N-1层都不改变。
所以,我们可以通过调用上一题的递归函数求出F1(N-1),本题结果即为2*F1(N-1)+2。