先盗一张图:
正常的汉诺塔问题只要把A柱的所有盘子移动到C柱就好了,可以借助B柱。实现的逻辑如下:
void hanoi(int n,char a,char b,char c) { ans++; if(n==1) { cout<<a<<"->"<<c<<endl; return; } hanoi(n-1,a,c,b); cout<<a<<"->"<<c<<endl; hanoi(n-1,b,a,c); }
我们在做这一类问题的时候如果从递归的终止条件去考虑的话,会容易很多。
我们就先看递归的终止条件
只剩一个盘子的时候,直接把A柱的盘子移动到C柱即可
否则,我们就要把A柱上的n-1个盘子从A柱借助于C柱移动到B柱
之后我们就可以顺理成章地把A柱上面剩下的最大的盘子移动到C柱了
最后我们需要把刚才移动到B柱上面的所有的盘子借助于A柱移动到C柱
我们只需要知道这个过程,具体的细节程序会帮着我们去做的
考虑问题的变式,只允许A和B之间,B和C之间发生盘子的移动。
下面先给出代码:
void hanoi2(int n,char a,char b,char c) { ans+=2; if(n==1) { cout<<a<<"->"<<b<<endl; cout<<b<<"->"<<c<<endl; return; } hanoi2(n-1,a,b,c); cout<<a<<"->"<<b<<endl; hanoi2(n-1,c,b,a); cout<<b<<"->"<<c<<endl; hanoi2(n-1,a,b,c); }
我们同样先考虑只有一个盘子的情况,很显然是A->B,然后B->C
否则,我们需要递归完成如下操作
先把A上面的n-1个盘子经过B柱移动到C柱(这是一个递归的过程,不要在这里产生疑问,因为递归的过程中问题会分解)
这时候A上面只剩一个大盘子了,我们顺理成章地将其移动到B柱
然后我们要做的是把C柱上面的n-1个盘子经由B柱移动到A柱,这是为啥呢?是为了给刚才放在B柱上面的那个大盘子腾地方。
腾完了地方,就可以把刚才放在B柱上面的那个大盘子顺理成章地移动到C柱
最后再递归处理子过程,把A上的n-1个盘子经由B柱移动到C柱。
我们总结一下一共需要多少步,第一种情况需要2^n-1,第二种情况需要3^n-2,具体为什么可以根据递归函数的特点得知。
总的程序如下:
1 #include<iostream> 2 using namespace std; 3 int ans=0; 4 void hanoi(int n,char a,char b,char c) 5 { 6 ans++; 7 if(n==1) 8 { 9 cout<<a<<"->"<<c<<endl; 10 return; 11 } 12 hanoi(n-1,a,c,b); 13 cout<<a<<"->"<<c<<endl; 14 hanoi(n-1,b,a,c); 15 } 16 void hanoi2(int n,char a,char b,char c) 17 { 18 ans+=2; 19 if(n==1) 20 { 21 cout<<a<<"->"<<b<<endl; 22 cout<<b<<"->"<<c<<endl; 23 return; 24 } 25 hanoi2(n-1,a,b,c); 26 cout<<a<<"->"<<b<<endl; 27 hanoi2(n-1,c,b,a); 28 cout<<b<<"->"<<c<<endl; 29 hanoi2(n-1,a,b,c); 30 } 31 int main() 32 { 33 int n; 34 cin>>n; 35 hanoi2(n,'A','B','C'); 36 cout<<ans<<endl; 37 return 0; 38 }