汉诺塔问题(C语言,递归)

问题:

寺院里有3根柱子,第一根有64个盘子,从上往下盘子越来越大。方丈要求小和尚把这64个盘子全部移动到第3跟柱子上。在移动的时候,始终只能小盘子压着大盘子,而且每次只能移动一个。

Hanoi Tower 的移动次数,思路:

先:

  • 第一根柱子标记为a
  • 第二根柱子标记为b
  • 第三根柱子标记为c
  • 设盘子有n个

根据移动盘子的规则,要把a上n个盘子全部移动到c上,无法判断最顶上的盘子先要放在哪儿(是放在b上还是c上,无法轻易判断 ),但是可以确定的一点是:

  • 第一步:先把a上的前(n-1)个盘子放到b上
  • 第二步:再把a上最下面的盘子放在c上(只有这一步可以直接完成)
  • 第三步:最后把b上的(n-1)个盘子放在c上

第一步,第三步怎么完成盘子的移动是个难题,
但是第一步中把(n-1)个盘子从a放到b上,和第三步中把(n-1)个盘子从b放到c上,他们的执行过程和上面的三个步骤是一样的,只是规模变小了,所以这是很明显的递归思想。

  • 注意:a到c的意思是:a最上面的盘子放到c上(便于下面的理解)
  • 假设n = 1,移动 1 次(a到c); ( 1 个盘子从一根柱子移动到另一个柱子上的移动次数都是这)
  • 假设n = 2,移动3次(第一步:a到b,第二步:a到c,第三步:b到c)即1 + 1 + 1 = 3次; ( 2 个盘子从一根柱子移动到另一个柱子上的移动次数都是这)
  • 假设n = 3,要移动 7 次(第一步:a到c,a到b,c到b,移动三次;第二步:a到c,移动一次;第三步:b到a,b到c,a到c;总共移动七次)即3 + 1 + 3次; ( 3 个盘子从一跟柱子移动到另一个柱子上的移动次数都是这)
  • 假设n = 4,要移动:7 + 1 + 7 = 15次(第一步和第三步的移动次数就是n=3的移动次数)
  • 当n = n,要移动:(n-1)个盘子的移动次数 + 1 + (n-1)个盘子的移动次数 。(可能和(n-1)个盘子的移动过程中盘子移动到哪个柱子的过程不一样,但是次数是一样的!)
  • 还可以看出移动n个盘子的次数是 (2的n次方 – 1)

所以64个盘子可不要轻易尝试,因为要移动18446744073709551616次(大约1800亿亿次),计算机可不一定有这运算能力

Hanoi Tower 的移动次数已经直接解决,但是移动步骤有什么规律呢?

假设有n个盘子:
(一)

  • 第一步:a最上面(n-1)个盘子移动到b
  • 第二步: a -> c,就是a上剩下的最大的盘子移动到c
  • 第三步: b上所有(即n-1个)盘子移动到c
  • 即a(n-1) -> b; a -> c; b(n-1) -> c;此时,盘子在a上,而b是媒介

(二)
然后第一步的实行过程(就是把a最上面(n-1)个盘子移动到b的实行过程):

  1. 把a最上面(n-2)个盘子移动到c
  2. 把a剩下的最上面的盘子放到b
  3. 把c上所有(即n-2个)盘子放到b
  4. 即a(n-2) -> c; a -> b; c(n-2) -> b,此时,盘子在a上,c是媒介

(三)
再然后1.中(把a最上面(n-2)个盘子移动到c的实行过程 (其实和(一)中的过程已经完全一样了,仅仅只是问题规模减小)

  • 把a最上面(n-3)个盘子移动到b
  • 把a剩下的最上面的盘子放到c
  • b上所有(即n-3个)盘子移动到c
  • 即a(n-3) -> b; a -> c; b(n-3) -> c,此时,盘子在a上,b是媒介

。。。。。。
于此类推,类比,规律已经出来了

#include<iostream>
using namespace std;

#define N 3  //盘子数 
int count = 0;  //统计移动次数

void Hanoi(int n,char x,char y,char z){ //x,y,z分别是三个柱子,
//第二个参数和第四个参数代表上面的盘子从这个柱子到那个柱子的移动过程
									 //n是盘子数 
	if(n == 1){
		cout<<x<<" -> "<<z<<endl; 
		count++;
		return;
	}
	Hanoi(n-1,x,z,y);  //第一步,把x最上面的n-1个盘子从x移动到y
	cout<<x<<" -> "<<z<<endl;   //第二步,再把x上剩下的最上面的盘子放在z上
	count++;
	Hanoi(n-1,y,x,z);  //第三步,把y上面的n-1个盘子从y移动到z
}

int main(){
	cout<<"盘子数:"<<N<<endl;
	cout<<"移动过程"<<endl;
	Hanoi(N,'a','b','c');
	cout<<"移动次数:"<<count<<endl; 
} 

参考资料:
《算法学习与应用 从入门到精通》张玲玲

    原文作者:舞伴问题
    原文地址: https://blog.csdn.net/Zhangguohao666/article/details/84074076
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞