【C++】汉诺塔问题的思路解释以及实现方法 hanoi

 问题描述:

大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?(每次只能移动1个盘子,大盘子只能放在小盘子下面)

也就是说,我们每次只能从任意一根柱子的最上端取下一个盘子,并把这个盘子放到任意一根柱子的最上端。

解决思路:

实际上这是一个递归的问题,我们先从正向思维看能否解决问题。

找规律:

我们把问题拆分来看,当有一个盘子时,当有两个盘子时......看能否找到一个能推广到整个正整数区域的规律。

当一个盘子的时候,我们只需要把A柱的盘子挪到C柱即可。

当两个盘子的时候,我们要把A柱的盘子挪到B柱,把A柱的下一个盘子挪到C柱,再把B柱的盘子挪到C柱。

当三个盘子的时候,情况如图所示:

【C++】汉诺塔问题的思路解释以及实现方法 hanoi_第1张图片

当四个盘子的时候,情况如图所示:

【C++】汉诺塔问题的思路解释以及实现方法 hanoi_第2张图片

 可以得出结论,挨个去写不仅浪费时间,较难按最优路径去挪动盘子,而且我们很难验证得出规律的真假。

所以我们直接取一个极大值n,从最后一个往前推,也就是递归。

递归法:

思路:乍一看没有思路,实际上我们可以简化问题。

上文提过,当只有一个盘子的时候,我们直接把这个盘子挪到C柱就可以,也就是无论如何,最后一个盘子一定是从B柱或者A柱直接挪到C柱。【这就是我们递归的终止条件】

首先,我们把A柱上的n个盘子看成两部分,第一部分是从1到n-1的盘子的集合,第二部分则是第n个盘子。那么在这时,我们就把问题简化成了两个盘子的情况,很简单,把集合挪到B柱,第n个盘子挪到C柱,集合挪到C柱,这就结束了。我们不需要考虑在这个过程中集合内部的盘子怎么挪动,因为后续可以对集合再度简化,也就是递归出答案。同样的,对于从1到n-1的盘子的集合来说,我们同样可以按上述方法分成两部分进行运算。直到这个集合只剩下第一个盘子,这时就成了只有一个盘子的情况,直接将这个盘子挪到C柱,就结束了运算。

简略图解: 

【C++】汉诺塔问题的思路解释以及实现方法 hanoi_第3张图片

实际上就是依次把整个集合的最大真子集移动到交换柱【除了要被挪动的集合所在的柱子和C柱之外的那个柱子,在上图过程1中,B柱是交换柱,过程3中,A是交换柱】,最下方的最大盘子放到C柱的过程!

函数实例:【n代表总共的盘子个数,a c b代表A C B柱】

int hanoi(int n, char a, char c, char b)
{      
	if (n == 1)
	{
		sum++;
		cout << "from:" << a << " to:" << c << endl;
		return 0;
	}
	else
	{
		hanoi(n - 1, a, b, c);
		sum++;
		cout << "from:" << a << " to:" << c << endl;
		hanoi(n - 1, b, c, a);
	}
}

举个例子:

按照上边的程序,我们模拟一下n=3时的情况,传入 3, 'A', 'C', 'B' ,n>1,进入else,递归 2, 'A', 'B' , 'C' ,n>1,进入else, 递归 1, 'A', 'B' , 'C' ,n=1,进入if,sum=1,第一个盘子从A到C,返回到上一层,sum=2,第二个盘子从A到B,进入最下方的递归,传入  1 , 'C' , 'B' , 'A'  【注意,最上层递归传入的实参为a b c,所以形参b c a对应着的实参为a b c】第一个盘子从C到B,sum=3............得出和我们正向得出的挪动路线相同。n=4,n=5......这些情况也都符合,我们就假定这个程序是正确的。

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