[DNFM0019] 汉诺塔算法

一、原理

河内之塔(Towers of Hanoi)是法国人M.Claus(Lucas)于1883年从泰国带至法国的,河内为越战时北越的首都,即现在的胡志明市。1883年法国数学家 Edouard Lucas曾提及这个故事,据说创世纪时Benares有一座波罗教塔,是由三支钻石棒(Pag)所支撑,开始时神在第一根棒上放置64个由上至下依由小至大排列的金盘(Disk),并命令僧侣将所有的金盘从第一根石棒移至第三根石棒,且搬运过程中遵守大盘子在小盘子之下的原则,若每日仅搬一个盘子,则当盘子全数搬运完毕之时,此塔将毁损,而也就是世界末日来临之时。

解法:

案例1 - 假设只有一个盘子的时候,就只有一个步骤,将第1个盘子从A移动到C。

步骤  盘子编号   源柱子   目的柱子

  1          1            A            C *

案例2 - 如果有两个盘子。

步骤  盘子编号   源柱子   目的柱子

  1           1           A            B

  2           2           A            C *

  3           1           B            C

扫描二维码关注公众号,回复: 2676704 查看本文章

案例 3  - 如果有三个盘子。

步骤  盘子编号   源柱子   目的柱子

  1         1         A            C

  2         2           A        B

  3         1             C             B

  4         3             A             C *

  5         1             B             A

  6         2             B             C

  7         1             A             C

现在开始找规律,我们要做的最重要的一件事情就是永远要把最底下的一个盘子从A移动到C,这个A和C不是固定不变的,有时我们需要将B看成C,有时需要将B看成A。看看上面从1个盘子的移动到3个盘子的移动,在移动记录中,当盘子的编号和盘子数量相同的时候,他们的步骤都是从A移动到C (看'*'标记的部分),其它的步骤对等。

再观察第3个案例中的第1-3步和第5-7步,第1-3步目的是从A移动到B,如果我们把B当作终点,那么这里的第1-3步理解起来和第2个案例的三个步骤完全相同,都是通过一个柱子来移动,和第2个案例比起来在后面加括号来表示:

1      1      A      C      (A -> B)

2      2      A      B      (A -> C)

3      1      C      B      (B -> C)

总结:将柱子B看成C,将C看成中转柱子。

第5-7步目的是从B移动到C如果我们把C当作终点,那么这里的5-7步理解起来和上面也是一样的,和第2个案例的三个步骤也完全相同。和第2个案例比起来就是:

5      1      B      A    (A -> B)

6      2      B      C    (A -> C)

7      1      A      C    (B -> C)

总结: 将柱子B看成A,将A看成中转柱子。

根据这个演示可以明确几点规律:

1. 当盘子只有一个的时候,只有一个动作,从A移动到C即结束。

2. 当有N个盘子的时候,中间的动作都是从A移动到C,那么表示最下面的第N个盘子移动完毕。

3. 中间动作之上都可以认为是:从A移动到B,C做中转。

4. 中间动作之下都可以认为是:从B移动到C,A做中转。

2,3,4 可以表示为:

1      1      A      B

2      2      A      C

3      1      B      C

这种结构一直在重复进行。

至于代码中第1个参数为什么是DiskQuantity – 1,或者1。大家再回到上面看看是不是所有的步骤都是:

[ 1 ]   [ 1,2,1 ]   [ 1,2,1,3,1,2,1 ]

这种以盘子数对称的结构,而它前后都是重复1,2,1的过程。

二、Java源码

class HanoiTower
{

    public void MoveDisk(int N, char A, char B, char C)
    {   
        // If there's only one disk, then end.
        if (1 == N)
        {
            System.out.println(String.format("Move disk from position %c to %c",  A, C));
        }
        else
        {
            // Step 1 - Change B to C
            MoveDisk(N - 1, A, C, B);
            // Step 2 - No changes
            MoveDisk(1, A, B, C);
            // Step 3 - Change B to A
            MoveDisk(N - 1, B, A, C);
        }
    }

    public static void main(String[] args)
    {
        HanoiTower hanoi = new HanoiTower();

        int DiskQuantity = 3;

        hanoi.MoveDisk(DiskQuantity, 'A', 'B', 'C');
    }
}

输出结果:

DNFM0019(9)

猜你喜欢

转载自blog.csdn.net/hanjing_csdn/article/details/79506121