非曰能,但好学,欢迎一起交流学习
问题分析
递归是解决汉诺塔问题最常见的做法,大家都不懒得写,我就来写写~
递归步骤分析
汉诺塔问题要求在移动过程中,不出现大的盘子压在小的盘子上。如下图需要讲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;
}


京公网安备 11010502036488号