前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、汉诺塔

汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子, 其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。 并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。在进行转移操作时,都必须确保大盘在小盘下面,且每次只能移动一个圆盘,最终c柱上有所有的盘子且也是从上到下按从小到大的顺序。

1.1、解题思路

 两个盘子的情况:有两个盘子的话把1号盘先移到b柱,在把2号盘移到c柱,最后把b柱上的1号盘移到c柱就行了      

 这个时候,想象将上面的63个盘子看做一个整体,最下面的1个盘子看做一个整体,也是这样解决的。    那么接下来这62个盘子,再看做一个整体,依次下去,是不是就成功了,这样相当于是逆推回去了 。这样的话,我们就可以使用递归算法了 

1581935848647

解:

(1)n == 1

第1次  1号盘  A---->C       sum = 1 次

(2) n == 2

第1次  1号盘  A---->B

第2次  2号盘  A---->C

第3次  1号盘  B---->C        

sum = 3 次

(3)n == 3

第1次  1号盘  A---->C

第2次  2号盘  A---->B

第3次  1号盘  C---->B     //1,2,3 操作是经由A上的盘子经由C移动到B

第4次  3号盘  A---->C        

第5次  1号盘  B---->A

第6次  2号盘  B---->C

第7次  1号盘  A---->C      //5,6,7 操作是经由B上的盘子经由A移动到C  

sum = 7 次

不难发现规律:

1个圆盘的次数 2的1次方减1

2个圆盘的次数 2的2次方减1

3个圆盘的次数 2的3次方减1  

。  。   。    。   。 

n个圆盘的次数 2的n次方减1

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

求解汉诺塔问题最简单的算法还是同过递归来求。实现这个算法可以简单分为三个步骤:

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上;

1.2、算法


/**
 * 题目:汉诺塔
    汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,
    其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
    并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。在进行转移操作时,
    都必须确保大盘在小盘下面,且每次只能移动一个圆盘,最终c柱上有所有的盘子且也是从上到下按从小到大的顺序。
解题思路:
    有两个盘子的话把1号盘先移到b柱,在把2号盘移到c柱,最后把b柱上的1号盘移到c柱就行了,
    这个时候,想象将商品的63个盘子看做一个整体,最下面的1个盘子看做一个整体,也是这样解决的。
    那么接下来这63个盘子,再看做一个整体,依次下去,是不是就成功了,这样相当于是逆推回去了 。这样的话,我们就可以使用递归算法了
 */
public class 汉诺塔 {

    public static void method(int n, char A, char B, char C) {

        //如果只有一个盘子(此时盘子只在A上),则直接移动到C上
        if (n == 1) {
            move(A, C);
        } else {
            //将n-1个盘子由A经过C移动到B
            method(n - 1, A, C, B);

            //中间的一步是把最大的一个盘子由A移到C上去;
            move(A, C);

            //剩下的n-1盘子,由B经过A移动到C
            method(n - 1, B, A, C) ;
        }
    }
    public static int count  = 0 ;
    private static void move(char A, char C) {//执行最大盘子n的从A-C的移动
        System.out.println("第"+ (++count)+"次移动:" + A + "--->" + C);
    }

    public static void main(String[] args) {
        System.out.println("移动汉诺塔的步骤:");
        method(3, 'a', 'b', 'c');
    }
}

1.3、测试

public static void main(String[] args) {
    System.out.println("移动汉诺塔的步骤:");
    method(1, 'a', 'b', 'c');
}
移动汉诺塔的步骤
第1次移动:a--->c



public static void main(String[] args) {
    System.out.println("移动汉诺塔的步骤:");
    method(1, 'a', 'b', 'c');
}
移动汉诺塔的步骤
第1次移动:a--->b
第2次移动:a--->c
第3次移动:b--->c




public static void main(String[] args) {
    System.out.println("移动汉诺塔的步骤:");
    method(1, 'a', 'b', 'c');
}
移动汉诺塔的步骤
第1次移动:a--->c
第2次移动:a--->b
第3次移动:c--->b
第4次移动:a--->c
第5次移动:b--->a
第6次移动:b--->c
第7次移动:a--->c

ContactAuthor