3-算法思想之分治法-汉诺塔问题

算法–分治法之汉诺塔问题

问题描述

​ 汉诺塔问题起源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

​ 例如:从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的3个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。那么我们可以这样移动,先将最小的盘移动到C柱,然后将中间的盘移动到B柱,再将最小的盘移动到B柱,接着将最大的盘移动到C柱,紧接着将最小的盘移动到A柱,将中间的盘移动到C柱,最后将最小的盘也移动到C柱。这样通过7次移动就可以将三个圆盘从A柱移动到C柱。

问题分析

分析:如果A柱子上面有从小叠到大的n个圆盘,我们需要将问题简化,可以将上面n-1个圆盘看作一个整体M(n-1),下面最大的圆盘看作另一个整体N(1),那么我们就可以将问题简化为下面的形式:通过C柱子作为辅助将上面的整体M全部放到B柱子上,再将整体N从A柱子移动到C柱子上,再通过A柱子作为辅助将整体M全部放到C柱子上,其中A、B、C柱子是相对的,在每次递归中会不断的相对变换。

算法分析

实现汉诺塔算法只需要一个主体函数,函数负责以下三个步骤:

​ 1.利用目标柱为媒介,将上面n-1个圆盘从原始柱暂时移动到辅助柱

​ 2.将原始柱上的最后一个最大的圆盘移动到目标柱上

​ 3.将暂存在辅助柱上的n-1个柱子全部移动到目标柱上

​ Tips:其中1,3两步会不断进行递归,直到只需要移动一个盘子(即n==1)为止,即可实现汉诺塔算法。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdlib.h>
#include <cstring>
#include <iostream>

using namespace std;

void Move(char src, char dest)
{
cout << "move " << src << " to " << dest << endl;
}

int Hanoi(int n, char src, char medium, char dest)
{
static int sum = 0;
sum++;
if (n == 1) Move(src, dest);
else
{
//利用目标柱为媒介,将上面n-1个圆盘从原始柱暂时移动到辅助柱
Hanoi(n - 1, src, dest, medium);
//将原始柱上的最后一个最大的圆盘移动到目标柱上
Move(src, dest);
//将暂存在辅助柱上的n-1个柱子全部移动到目标柱上
Hanoi(n - 1, medium, src, dest);
}
return sum;
}

int main()
{
int n;
int a;
cin >> n;
a = Hanoi(n, 'A', 'B', 'C');
cout << a << endl;
return 0;
}