分治算法解决汉诺塔问题(Java实现)

文章收藏的好句子:没有天下,自己打天下;没有资本,自己赚资本;没有靠山,自己就是山。

目录

1、分治算法

     1、1 分治算法的基本介绍

     1、2 分治算法的步骤

     1、3 用分治算法解决汉诺塔问题

1、分治算法

1、1 分治算法的基本介绍

分治算法思想就是“分而治之”,将一个复杂的问题分为多个相似的子问题,又把子问题分为多个更小的子问题,直到最后子问题可以用最简单的方式直接求解,原问题的解就是为子问题解的合并;我们见到的二分搜索啊,棋盘模型啊,合并排序啊,快速排序啊,汉诺塔等经典算法,就是运用到分治算法的。


1、2 分治算法的步骤

(1)分解,将原问题分解为 N 个规模较小,相互独立,与原问题形式相同的子问题。

(2)解决,如果子问题规模较小,那么直接求解;如果规模较大,那么递归求解。

(3)合并,将各个子问题的解合并为原问题的解。

1、3 用分治算法解决汉诺塔问题

为了能理解汉诺塔问题,我先来画一张图,如图1所示;

分治算法解决汉诺塔问题(Java实现)_第1张图片

有三根杆(编号A、B、C),在 A 杆自下而上、由大到小按顺序放置 N (这里图1的为3个)个金盘(如图1);游戏的目标是把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好;操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

为了更好的总结汉诺塔的规则,我们先用图1的来进行举例,按照游戏的规则,我们最终的结果是从 A 杆上全部移动到 C 杆上,从下而上盘的顺序是3、2、1 对不对;好,我们现在分3个步骤来移动盘子。

(1)将 B 杆作为中转杆,这一步我们最终先将 1、2 号盘拿到 B 杆上,才能将 3 号盘从 A 杆拿到 C 杆上对不对?先将 1 号盘拿到 C 杆上,再将 2 号盘拿到 B 杆上,又从 C 杆上拿走 1 号盘到 B 杆上,这时候操作完这一步骤得到如图2所示;

分治算法解决汉诺塔问题(Java实现)_第2张图片

(2)从 A 杆上直接从 3 号盘取出拿到 C 杆上,执行完这一步骤得到如图3所示;

分治算法解决汉诺塔问题(Java实现)_第3张图片

(3)将 A 杆作为中转杆,这一步我们的最终目的是将 B 杆上的 1、2 号盘拿到 C 杆上对不对?先从 B 杆上把 1 号盘拿到 A 杆上,再从 B 杆上把 2 号盘拿到 C 杆上,最后从 A 杆上把 1 号盘拿到 C 杆上,执行完这一步骤得到如图4所示;

分治算法解决汉诺塔问题(Java实现)_第4张图片

好,我们现在对这3个步骤进行总结一下,第一步骤移动了3次,第二步骤移动了1次,第三步骤移动了三次,就总共移动了7次,那么就得出总共移动的次数就等于2的 n 次方之后再减1就等于7,其中 n 表示一开始 A 杆上盘子的个数。

这里我们推理一下,n 表示一开始 A 杆上盘子的个数,当 n 为1的时候,只需要移动一次对不对?也就是直接将这个盘子拿到 C 杆上就好了;当 n 大于1的时候,就需要按照上面所说的分3个步骤来移动盘子对不对?其中第一步骤和第三步骤移动的次数是相同的对不对?而第二步骤只需要移动一次,根据总共移动的次数就等于2的 n 次方之后再减1这个规则得到,(2^n 表示2的n次方)第一步骤和第三步骤移动的次数就均为 (2^n - 2) / 2 。

当 n 大于1时,汉诺塔问题是一个递归问题,它的规则是这样的:第一次以 B 杆为中转杆,将1到n-1号的盘子搬到 B 杆上,然后从 A 杆上把 n 号的盘子拿到 C 杆上;第二次以 A 杆为中转杆,将1到n-2号的盘子搬到 A 杆上,然后从 B 杆上把 n-1 号的盘子拿到 C 杆上;第三次以 B 杆为中转杆,将1到 n-3号的盘子拿到 B 杆上,然后从 A 杆上把 n-2 号的盘子拿到 C 杆上;以此这样类推下去......直到把1号盘子拿到 C 杆上。

好,我们用 Java 代码实现一把

(1)新建一个 Test 类:

package com.xiaoer.demo;


public class Test {


  public static void main(String[] args) {
    hanoi(3,'A','B','C');
  }


  /**
   * 
   * @param n 表示盘子的个数
   * @param a 起始杆,也就是从这个杆子上拿的盘子放到其他杆子上
   * @param b 中转杆,不一定字母b就是中转杆,只要是第三个参数,只要是第三个参数,
   * 只要是第三个参数,就是中转杆
   * 
   * @param c 目标杆,也就是从其他杆子上拿的盘子放到这根杆子上
   */
  public static void hanoi(int n, char a, char b, char c) {
    if (n == 1) {
      System.out.println(a + "-->" + c);
    }else {
      
      /**
       * 第一步骤,当 n 一开始为3的时候,直接把1、2 号盘子移动到B杆上;
       * 推理,当n大于1并为其他数时,直接把1到(n-1)号盘子移动到B杆上
       * 
       */
      hanoi(n - 1, a, c, b);
      
      /**
       * 第二步骤,当n一开始为3的时候,直接把3号盘子拿到C杆上;
       * 推理,当n大于1并为其他数时,直接把n号盘子移动到C杆上
       */
      System.out.println(a + "-->" + c);
      
      /**
       * 第三步骤,当n一开始为3的时候,直接从B杆上把1、2号盘子拿到C杆上;
       * 推理,当n大于1并为其他数时,直接把1到(n-1)号盘子从A杆移动到C杆上
       */
      hanoi(n - 1, b, a, c);
    }
  }


}

程序运行结果如下所示;

分治算法解决汉诺塔问题(Java实现)_第5张图片

你可能感兴趣的:(算法,java,数据结构,深度学习,分治算法)