一文带你吃透汉诺塔和其变形题

普通汉诺塔

感兴趣的童鞋可以与我联系和交流~

汉诺塔(港台:河内塔)(Tower of Hanoi)是根据一个传说形成的数学问题:

有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:

  1. 每次只能移动一个圆盘;
  2. 大盘不能叠在小盘上面。

可以将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。

对于这个问题我们可以从简单的看起,然后发现规律。从规律中摸索出解决这个问题的办法。通常汉诺塔被作为学习递归的入门案例。这篇文章将吃透汉诺塔思想及其变形的题目。

我们从只有一个盘子的时候开始研究。很简单,直接把红色的盘子移到B上就可以了。

一个盘子汉诺塔.gif

现在我们来研究两个盘子的情况:

  • 我们的思路是先把最底下的大盘子放到B上,但是由于盘子大小不一样,所以我们得想办法先把上面的盘子放到C上,这样才可以把下面的大盘子放到B上,再把上面的小盘子放到B上
两个盘子汉诺塔.gif

步骤:

1. 红色盘子移到C上
2. 黄色盘子移到B上
3. 红色盘子移到B上

此时两个盘子都在B上,并且红色盘子在黄色盘子上面

接下来再来看三个盘子的情况

  • 要都放到B上,就必须先把蓝色上面的两个盘子想办法移到C 上,这样才能把蓝色的盘子移到B上。因此,先把红色和黄色移到C上,现在问题变成了只有两个盘子的情况,也就用到了上面的三步。然后再把蓝色盘子移到B上。最后把黄色和红色盘子移到B上,也就又回到了上面只有两个盘子的情况
三个盘子汉诺塔.gif

步骤:

1. 把红色盘子移到B上
2. 把黄色盘子移到C上
3. 把红色盘子移到C上
4. 把蓝色盘子移到B上
5. 把红色盘子移到A上
6. 把黄色盘子移到B上
7. 把红色盘子移到B上

可见,完全可以把三个盘子的情况转化成两个盘子的情况,然后得以解决。

根据上面的规律可以知道:

n盘子从A移动到B = 先把 n - 1 个盘子从A移动到C + 把最底下的盘子移动到B + 最后把 n - 1个盘子从C移动到B上

即 : 公式 H ( n ) = H ( n - 1 ) + 1 + H ( n - 1 )

数学方法适合计算移动的次数,递归法计算次数和显示移动路径均可,后同。

现在思路清楚了,我们来讲它的两种解法:

解法一(数学方法):

//换元法+数学归纳法

H( n ) = H( n - 1 ) + 1 + H( n - 1 )
       = 2 * H( n - 1 )  +  1
//两边同时加1
H( n ) + 1 = 2 * [ H( n - 1 ) + 1 ]
//令U( n ) = H( n ) + 1
H( n ) + 1 = 2 * [ H(n - 1 ) + 1 ]
//则可变为
U( n ) = 2 * U( n - 1 )    
       = 2^2 * U( n - 2 ) = ······
       = 2^(n-1) * U(1) = 2^n
//因此解得 H( n ) = 2^n - 1

解法二(递归法):

unsigned int count = 0;
void hanio(int n,char A,char B,char C){
    
    if(n==1)
       cout<<"Put "<<n<<" from "<<A<<" to "<<B<<endl;// 如果只有一个,那么把这个盘子直接放到B上就可以
       count += 1;
    else
    {
       hanio(n-1,A,C,B);    //借助B把前n-1个盘子从A移动到C上
       cout<<"Put "<<n<<" from "<<A<<" to "<<B<<endl;   //把最下面的盘子从A移动到B上
       count += 1;
       hanio(n-1,C,B,A);   //借助A把刚才上面的n-1个盘子从C移动到B上
}

变形题1(变化条件):

假如有2N个盘子,盘子种类有N种,并且每种盘子有两个(这两个大小和颜色完全相同)

思路点拨:以前移动1个盘子:例如红色移动到C上,现在无非就是把两个红色的移动到C上,因为这两个盘子完全一样,所以只要把原来的移动一次,现在改成移动两次就可以了

新2n盘子从A移动到B = 2 * 之前n个盘子移动次数

因此,依然有两种解法:

解法一(数学方法):

//换元法+数学归纳法
//G(n)代表新的规则下的移动次数
G( n ) = 2 * H( n )
       = 2 * ( 2^n - 1 )
       = 2^(n + 1) - 2

解法二(递归法):

unsigned int count = 0;
void hanio(int n,char A,char B,char C){
    
    if(n == 2 ){
       cout<<"Put "<<n<<" from "<<A<<" to "<<B<<endl;// 如果只有两个,那么把这两个盘子直接放到B上就可以
       cout<<"Put "<<n-1<<" from "<<A<<" to "<<B<<endl;
       count += 2;
    }
    else
    {
       hanio(n-2,A,C,B);    //借助B把前n-2个盘子从A移动到C上
       cout<<"Put "<<n - 1<<" from "<<A<<" to "<<B<<endl;   //把最下面的两个盘子从A移动到B上
       cout<<"Put "<<n<<" from "<<A<<" to "<<B<<endl;   //
       count += 2;
       hanio(n-2,C,B,A);   //借助A把刚才上面的n-2个盘子从C移动到B上
}

变形题2(变化条件):

假如A和B直接不能直接移动,那么怎么解决?

思路点拨:既然不能直接在A和B直接移动,那么想从A移动到B,或者从B移动到A,都需要借助C来实现,先移动到C再移动到A或B

步骤:

1. 先把 n - 1 个通过C移动到B上 
2. 把最底部的移动到C上
3. 再通过C把B上的n-1个移动到A上
4. 把底部的移动到B上
5. 最后把n - 1 个通过C移动到B上

移动n个盘子需要的次数 = 通过C移动n-1个盘子到B的次数 + 把最底部移动到C上的次数 + 通过C再次移动n-1个盘子到A的次数 + 把最底部盘子移动到B上次数 + 通过C把n-1个盘子移动回B的次数

因此,依然有两种解法:

解法一(数学方法):

//为了区别此处改为G(n)
G( n ) = G( n - 1 ) + 1 + G( n - 1 ) + 1 + G( n - 1 )
// 同理,此次省略数学推导过程,证明思路和第一个一样,有兴趣可以联系作者
       = 3^n - 1

解法二(递归法):

unsigned int count = 0;
void hanio(int n,char A,char B,char C){
    
    if(n == 1 ){
       cout<<"Put "<<n<<" from "<<A<<" to "<<B<<endl;// 如果只有一个,那么把这个盘子先放到C上
       cout<<"Put "<<n<<" from "<<C<<" to "<<B<<endl;// 把这个盘子再放到B上
       count += 2;
    }
    else
    {
       hanio(n-1,A,B,C);                                 //把n-1个通过C移动到B上 
       cout<<"Put "<<n<<" from "<<A<<" to "<<C<<endl;   //把最底部的移动到C上
       count += 1;
       hanio(n-1,B,A,C);                                //再通过C把B上的n-1个移动到A上
       cout<<"Put "<<n<<" from "<<C<<" to "<<B<<endl;   //把底部的移动到B上
       count += 1;        
       hanio(n-2,A,B,C);                                 //最后把n-1个通过C移动到B上
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 题目描述 在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘...
    珺王不早朝阅读 793评论 0 0
  • 前言 相信学过《数据结构与算法》这门课程的同学都有听过汉诺塔问题,但是可能在大学的时候没有钻研过,或者在学的时候就...
    郑土强ztq阅读 2,939评论 2 3
  • 原文链接(转载请注明出处)汉诺塔的图解递归算法 起源 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大...
    Dmego阅读 1,532评论 0 0
  • 引 前段时间做了一道题,要求实现汉诺塔游戏的自动解题动画: 汉诺塔游戏应该都了解规则: 1、将盘子全部移动到塔C2...
    Cloudox_阅读 647评论 0 3
  • 一个n层的汉诺塔,从A移动到C 由于汉诺塔问题本身的限制,我们最先能思考到的点是第n层最后肯定是要放在C的最下面的...
    愤怒的熊猫V阅读 913评论 0 0