非曰能,但好学,欢迎一起交流学习
问题分析
递归是解决汉诺塔问题最常见的做法,大家都不懒得写,我就来写写~
递归步骤分析
汉诺塔问题要求在移动过程中,不出现大的盘子压在小的盘子上。如下图需要讲src柱子上的n个盘子移动到target上柱子上。假设我们已经可以按照规则将上面n-1个柱子移动另外的柱子上。,怎完成n个盘子移动的任务步骤为:
- 将src柱子上的上面n-1层盘子移动到mid柱子(非src和target的中间过渡的柱子)上。
- 将第n的盘子移动到target上柱子上。
- 将mid柱子上的n-1个盘子移动到target柱子上。
对于n=1的情况,不需要借助mid柱子,直接将一个盘子拎到target上就ok了。
移动次数分析
用表示移动n个盘子需要移动的次数,则有移动次数的递推关系式
可以计算得到移动次数,即移动过程中存在的状态数为次.
代码实现
递归中的步骤实现是明显的stack压栈出栈操作,但考虑到可视化的方便,这里采用用三个vector来表示三个塔上串的柱子状态(本人觉得stack的数据结构是C++中最没必要的数据结构)。实现时可以考虑分成两层:一是“逻辑层”,将负责每个移动过程中修改三个vector变量;另一个为“可视化层”,负责根据三个vector的状态,来打印出结果。
最后附上本人拙劣的代码如下。
#include <bits/stdc++.h> using namespace std; class Solution { public: int n; vector<int> A[3]; void read() { cin>>n; for(int i=0; i<n; i++) A[0].push_back(n-i); } void printDim() { int cols=3*(2*n+1)+4; for(int j=0; j<cols; j++) printf("-"); printf("\n"); } void move(int n, int src, int target) { if(n==1) { A[target].push_back(A[src].back()); A[src].pop_back(); printDim(); show(); return ; } int mid=0; for(; mid<3; mid++) if(mid!=src && mid!=target) break; move(n-1,src,mid); A[target].push_back(A[src].back()); A[src].pop_back(); printDim(); show(); move(n-1,mid,target); } void show() { // show the 3 vectors in A int cols=3*(2*n+1)+4; for(int j=0; j<cols; j++) printf("."); printf("\n"); for(int r=0; r<=n; r++) { printf("."); for(int k=0; k<3; k++) { int tmp = n-r<A[k].size()? A[k][n-r] : 0; for(int j=0; j<n-tmp; j++) printf("."); if(tmp==0) printf("|"); else { for(int j=0; j<1+2*tmp; j++) printf("*"); } for(int j=0; j<n-tmp; j++) printf("."); printf("."); } printf("\n"); } } void process() { show(); if(n%2==0) move(n,0,2); else move(n,0,1); } }; int main() { Solution s; s.read(); s.process(); return 0; }