汉诺(Hanoi)塔


一、背景介绍

在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片,一次只移动一片,不管在哪根针上,小片必在大片上面。当所有的金片都从梵天穿好的那根针上移到另外一概针上时,世界就将在一声霹雳中消灭,梵塔、庙宇和众生都将同归于尽。


二、数学定义

从左到右有三根柱子A、B、C,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。

我们记移动总次数为sum。

不难发现,

当n==1时,sum=1,

第一次:A→C;

当n==2时,sum=3,

第一次:A→B,

第二次:A→C,

第三次:B→C

当n==3时,sum=7;

​ 第一次: A→C,
​ 第二次: A→B,
​ 第三次: C→B,
​ 第四次 :A→C,
​ 第五次 :B→A,
​ 第六次 :B→C,
​ 第七次: A→C;

因此,

不难发现规律:

​ 1个圆盘的次数 2的1次方减1
​ 2个圆盘的次数 2的2次方减1
​ 3个圆盘的次数 2的3次方减1
……
​ n个圆盘的次数 2的n次方减1

故:移动次数为:2^n - 1。


三、递归算法

void hanoi(int n, int a, int b, int  c) {
if (n > 0) {
hanoi(n - 1, a, c, b);
move(a, b);
hanoi(n - 1, c, b, a);
}
}

其中,hanoi(n, a, b, c)表示将塔座A上自下而上,由大到小叠放在一起的n个圆盘依移动规则移至塔座B上并按照同样的顺序叠放。在移动过程中,以塔座C作为辅助塔座。move(a, b)表示将塔座A上编号为n的圆盘移到塔座B上。

实现这个算法可以简单分为三个步骤:

(1) 把n-1个盘子由A 移到 B;
(2) 把第n个盘子由 A移到 C;
(3) 把n-1个盘子由B 移到 C;

从这里入手,在加上上面数学问题解法的分析,我们不难发现,移到的步数必定为奇数步:

(1)中间的一步是把最大的一个盘子由A移到C上去;
(2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到了B上,
(3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上;


四、完整代码

#include<iostream>
#include<math.h>
using namespace std; void hanoi(int n, char A, char B, char C) {
if (n == 1)
cout << "将圆盘" << n << "从" << A << "移动到" << C << endl;
else {
hanoi(n - 1, A, C, B);
cout<< "将圆盘" << n << "从" << A << "移动到" << C << endl;
hanoi(n - 1, B, A, C);
}
} int main() {
int n;
cout << "请输入A上圆盘的个数n:";
cin >> n;
cout << endl;
hanoi(n, 'A', 'B', 'C');
cout << endl;
int sum = pow(2, n) - 1;
printf("移动的总次数sum为:%d",sum);
return 0;
}

五、非递归(拓展)

该方法设计了一个数据结构 struct act {int flag,num; char x, y, z;} S[2000]; 存储当前操作信息,其中flag==0表示直接移动num号圆盘,否则需要进一步分解;num表示当前操作移动盘子的编号,x,y,z表示当前操作对应的3个塔柱,分别是出发柱,中点柱和目标柱。

void Hanoi_1(int n, char a, char b, char c)//非递归算法1
{
struct act { int flag, num; char x, y, z; } S[2000]; //存储当前操作信息,flag==0表示直接移动num号圆盘,否则需要进一步分解
int top, m;
char ta, tb, tc; S[0].flag = 1;//初值入栈
S[0].num = n;
S[0].x = a;
S[0].y = b;
S[0].z = c;
top = 0;
int count = 0;
while (top >= 0)
{
if (S[top].flag == 0 || S[top].num == 1)//直接将num号圆盘从x移动到z
{
printf("%d: %d %c -> %c ", ++count, S[top].num, S[top].x, S[top].z);
--top;
}
else
{ //提取栈顶信息
m = S[top].num;
ta = S[top].x;
tb = S[top].y;
tc = S[top].z;
//将 Hanoi(n-1, b, a, c); 操作入栈 ,覆盖原栈顶信息
S[top].num = m - 1;
S[top].x = tb;
S[top].y = ta;
S[top++].z = tc;
//将 将第m个盘从a柱移动到c柱 操作入栈
S[top].flag = 0;
S[top].num = m;
S[top].x = ta;
S[top++].z = tc;
//将 Hanoi(n-1, a, c, b); 操作入栈
S[top].flag = 1;
S[top].num = m - 1;
S[top].x = ta;
S[top].y = tc;
S[top].z = tb;
}
}
}

以上非递归算法利用栈模拟递归过程的基本方法。对于有n个盘子的汉诺塔问题,需要操作的步骤为2^n – 1,如果每一个步骤看成一个节点,则刚好构成一棵满二叉树,树高h与盘子数量的关系为h==n。结点所在的层数与对应盘子的编号关系为level==n+1-level,即盘子1在第n层,盘子n在第1层;若某个结点的操作为“盘子n从A->C”,则其左孩子操作为“盘子n-1从A->B”,右孩子操作为“盘子n-1从B->C”;中序遍历满二叉树,结点的编号恰好对应移动的次序。

因此我们可以构造一棵满二叉树,然后中序遍历该二叉树。

void Hanoi_3(int n, char a, char b, char c)
{
struct act { int num; char x, y, z; } BT[132000];
//存储每一步操作的满二叉树
int S[MAX] = { 0 };
int i, top, count = 0; BT[1].num = n;//为根结点赋值
BT[1].x = a;
BT[1].y = b;
BT[1].z = c;
n = pow(2, n - 1);
for (i = 1; i < n; i++)//为每个节点的左右孩子赋值
{
BT[i + i].num = BT[i + i + 1].num = BT[i].num - 1;
BT[i + i].x = BT[i + i + 1].y = BT[i].x;
BT[i + i].z = BT[i + i + 1].x = BT[i].y;
BT[i + i].y = BT[i + i + 1].z = BT[i].z;
} //中序遍历满二叉树
n += n;
i = 1;
top = -1;
while (i < n || top >= 0)
{
if (i < n)//入栈,并搜索左孩子
{
S[++top] = i;
i += i;
}
else//输出并退栈,搜索右孩子
{
i = S[top--];
printf("%d: %d %c -> %c ", ++count, BT[i].num, BT[i].x, BT[i].z);
i += i + 1;
}
}
}

鸣谢:http://blog.csdn.net/qiaoruozhuo

算法2:Hanoi塔的更多相关文章

  1. 算法训练 Hanoi问题

      算法训练 Hanoi问题   时间限制:1.0s   内存限制:512.0MB      问题描述 如果将课本上的Hanoi塔问题稍做修改:仍然是给定N只盘子,3根柱子,但是允许每次最多移动相邻的 ...

  2. 栈与递归的实现(Hanoi塔问题等等)

    函数中有直接或间接地调用自身函数的语句,这样的函数称为递归函数.递归函数用 得好,可简化编程工作.但函数自己调用自己,有可能造成死循环.为了避免死循环,要 做到两点: (1) 降阶.递归函数虽然调用自 ...

  3. 经典递归算法研究:hanoi塔的理解与实现

    关于hanoi塔的原理以及概念,请Google,访问不了去百度. 主要设计到C中程序设计中递归的实现: 主代码实现如下: void hanoi(int src, int dest, int tmp, ...

  4. (转)Hanoi塔问题分析

    转自:http://shmilyaw-hotmail-com.iteye.com/blog/2077098 简介 关于Hanoi塔问题的分析,在网上的文章都写烂了.之所以打算写这篇文章,更多的是针对这 ...

  5. Hanoi塔问题——递归

    /////////////Hanoi塔问题///////#include<iostream>using namespace std;void hanoi(int i,char A,char ...

  6. Java实现 蓝桥杯VIP 算法训练 Hanoi问题

    问题描述 如果将课本上的Hanoi塔问题稍做修改:仍然是给定N只盘子,3根柱子,但是允许每次最多移动相邻的M只盘子(当然移动盘子的数目也可以小于M),最少需要多少次? 例如N=5,M=2时,可以分别将 ...

  7. (算法)Hanoi Problem汉诺塔问题

    Problem: There are three poles and N disks where each disk is heaver than the next disk. In the init ...

  8. Hanoi塔问题

    说明:河内之塔(Towers of Hanoi)是法国人M.Claus(Lucas)于1883年从泰国带至法国的,河内为越战时北越的首都,即现在的胡志明市:1883年法国数学家 Edouard Luc ...

  9. 【题解】Hanoi塔问题

    题目描述 有三根柱A,B,C.在柱A上有N块盘片,所有盘片都是大的在下面,小片能放在大片上面.并依次编好序号,现要将A上的N块片移到C柱上,每次只能移动一片,而且在同一根柱子上必须保持上面的盘片比下面 ...

  10. python算法-汉诺塔问题

    汉诺塔问题   初始状态: 思考:当盘子的个数是3的时候,大家写出移动顺序 移动的步骤: 3个盘子,从a到c 1.前面两个盘子,从a到b 1)把前面一个盘子,从a到c a->c 2)把第二个盘子 ...

随机推荐

  1. HDFS核心概念与架构

    HDFS简介 HDFS是Hadoop项目的核心子项目,在大数据开发中通过分布式计算对海量数据进行存储与管理,它基于流数据模式访问和处理超大文件的需求而开发,可以运行在廉价的商用服务器上,为海量数据提供 ...

  2. Note -「SOS DP」高维前缀和

    本文差不多算是翻译了一遍 CF blog?id=45223 就是抄了一遍,看不懂可以去原文. 当然我的翻译并不是完全遵从原文的. Part. 1 Introduction 平时我们怎么求高维前缀和?容 ...

  3. 【解惑】时间规划,Linq的Aggregate函数在计算会议重叠时间中的应用

    在繁忙的周五,小悦坐在会议室里,面前摆满了各种文件和会议安排表.她今天的工作任务是为公司安排下周的50个小会议,这让她感到有些头疼.但是,她深吸了一口气,决定耐心地一个一个去处理. 首先,小悦仔细地收 ...

  4. Teamcenter RAC 开发之《新建Item》

    private TCComponentItem createOperation(String itemName,String itemType) { //obejct_name itemType tr ...

  5. 熟练掌握并充分利用CSS3的新特性,更新完毕。

    1.1  尝试新颖的CSS3特性 首先,我们来看一个具体的案例.  https://code.juejin.cn/pen/7277536985772720139   1.2  CSS3新特性简介和浏览 ...

  6. Shell 文件或目录操作符(-e、-d、-f、-r、-w、-x)

    操作符 操作符 含义-e 判断对象是否存在(Exist),若存在则结果为真-d 判断对象是否为目录(Directory),是则为真-f 判断对象是否为一般文件(File),是则为真-r 判断对象是否有 ...

  7. 入门篇-其之五-Java运算符(上)

    一元运算符之正负号 Java支持多种一元运算符,一元运算符中的"一元"是指一个操作数.我们初中学过的正负号就属于一元运算符,因为正负号后面只有一个数字. 正数使用+表示,其中+可以 ...

  8. 可观测性数据收集集大成者 Vector 介绍

    如果企业提供 IT 在线服务,那么可观测性能力是必不可少的."可观测性" 这个词近来也越发火爆,不懂 "可观测性" 都不好意思出门了.但是可观测性能力的构建却着 ...

  9. GPL协议原文及中文翻译

    GPL协议原文及中文翻译 原文参考链接 翻译参考链接 原文 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 19 ...

  10. 长程 Transformer 模型

    Tay 等人的 Efficient Transformers taxonomy from Efficient Transformers: a Survey 论文 本文由 Teven Le Scao.P ...