简单解决 Hanoi 汉诺塔

       汉诺塔问题,当作只有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;
	
}

你可能感兴趣的:(c++)