汉诺塔问题,当作只有2个盘子。每次都把问题分成 n-1(上面所有盘子)和1 (最下面一个盘子)来解决。
比如说:
上面n-1个盘子记为up,下面1个盘子记为down:
目标是A->C:up移到B,down移到C,up移到C。 ——解决
那目标换成A->B呢:up移到C,down移到B,up移到B。——解决
以此类推,目标是B->A, B->C, C->A, C->B呢?
多写几遍能发现,规律就是起点柱,借助第三方柱子,最后移到终点柱。比如目标A->C:A是起点柱C是终点柱,第三方柱子就是B,我们的up盘(上面n-1个盘子)要借第三方柱子B让开,让最下面1个盘子能够出来去到终点柱C,然后up盘再从第三方柱子B移动到终点柱C。
用一个函数表示这个操作:
move(盘子数,起点柱子,终点柱子)
【 move (int N, char from, char to)】
参数加上第三方柱子也可以,不过有3根柱子,起点终点确定了剩下的就是第三方柱子。其实,参数加上了第三方柱子,就是标准汉诺塔方法中最外层套的那个函数。
递归。用子问题不断解决。当move移动盘子数为1的时候给递归出口。标准的Hanoi汉诺塔代码还会在外面套多一个函数。这样可以知道是在移动第几个盘子,但是那个第一眼没那么好看懂。
整个解决方案都只是自己的理解,下面是代码,缺点是不知道现在移动的是第几个盘子。
#include
using namespace std;
int CallTime = 0;
void move(int n, char from, char to){
CallTime += 1;
if(n == 1){
cout << "move one from " << from << " to " << to << endl;
return;
}
// 下面的写着写着发现规律
/*if(from == 'A' && to == 'C'){
move(n-1, 'A', 'B');
move(1, 'A', 'C');
move(n-1, 'B', 'C');
}
if(from == 'A' && to == 'B'){
move(n-1, 'A', 'C');
move(1, 'A', 'B');
move(n-1, 'C', 'B');
}
if(from == */
if(from + to == 'A' + 'C'){
move(n - 1, from, 'B');
move(1, from, to);
move(n - 1, 'B', to);
return;
}
if(from + to == 'A' + 'B'){
move(n - 1, from, 'C');
move(1, from, to);
move(n - 1, 'C', to);
return;
}
if(from + to == 'B' + 'C'){
move(n - 1, from, 'A');
move(1, from, to);
move(n - 1, 'A', to);
return;
}
printf("unknown: n = %d, from = %c, to = %c",n, from, to);
}
int main(){
// 盘子数
int N;
cout << "输入盘子数:"; cin >> N;
// 移动
auto StartTime = clock(); // 计时开始
move(N, 'A', 'C'); // 移动,将N个盘从A移动到C
auto EndTime = clock(); // 计时结束
// 结果
cout << "用时:" << double(EndTime - StartTime)/CLOCKS_PER_SEC << " s" << endl;
cout << "递归调用次数(算上了第一次进入函数):" << CallTime << endl;
}