精华内容
下载资源
问答
  • 1.2 Hanoi塔问题

    2020-09-19 16:17:24
    Hanoi塔的初始状态是所有的圆盘全部大小有序地叠放在一个塔座上,最大圆盘放在最底层,如下图所示。       Hanoi塔问题的目标是:将所有的圆盘从原始塔座(第一个塔座)上移动到目标...

    1.2 Hanoi塔问题

    问题描述

          Hanoi塔问题由3个竖立着的塔座和一组中间有孔的圆盘组成,圆盘中间有个孔以便沿塔座柱移动叠放,每个圆盘有不同的直径。Hanoi塔的初始状态是所有的圆盘全部大小有序地叠放在一个塔座上,最大圆盘放在最底层,如下图所示。
    p1
          Hanoi塔问题的目标是:将所有的圆盘从原始塔座(第一个塔座)上移动到目标塔座(第三个塔座)上。此外,第二个塔座是辅助塔座,用于存放移动过程中的圆盘,圆盘移动必须遵守以下三条规则:

    • 每次只能移动一个圆盘
    • 不能将大圆盘放在小圆盘上
    • 除非圆盘正处于在塔座间移动的过程中,否则所有圆盘必须在某个塔座上。

    分析

    1. 基本策略
      (1)将最顶上的N-1个圆盘从原始塔座移动到辅助塔座
      (2)将最大的圆盘从原始塔座移动到目标塔座
      (3)将N-1个圆盘从辅助塔座移动到目标塔座
    2. 解释
      (1)递归思想:要将最顶上的N-1个圆盘从原始塔座移动到辅助塔座,相当于将第N-1个圆盘和最顶上的N-2个圆盘移动到辅助塔座;将最顶上的N-2个圆盘移动到辅助塔座,相当于将第N-2个圆盘和最顶上的N-3个圆盘移动到辅助塔座…当原始塔座上只剩一个圆盘时,可将此圆盘直接移动到目标塔座上,比如移走最顶上N-1个圆盘后,可直接将第N个圆盘移到目标塔座上。
      (2)在移动过程中,将最顶上的N-1个圆盘从原始塔座移动到辅助塔座后,又将第N个圆盘从原始塔座移动到了目标塔座,此时第N个圆盘已移动完毕,而前N-1个圆盘已全在辅助塔座上。现在辅助塔座上有圆盘,原始塔座上为空,此时在下一轮移动过程中,辅助塔座变为原始塔座,原始塔座变为辅助塔座。每一轮移动过程执行完后,原始塔座和辅助塔座的身份都要相互转换。(一轮移动过程 以将此时最大的圆盘移动完毕为一轮)
      (3)在一轮移动过程中,我们目的是将第N个圆盘从原始塔座移动到目标塔座,为了实现目的,需要先将前N-1个圆盘从原始塔座移动到辅助塔座,为第N个圆盘让路。此时对于前N-1个圆盘,目标是从原始塔座移动到辅助塔座,此时目标塔座变成了临时存放圆盘的空间(目标塔座与辅助塔座完成了身份转换)。

    代码

    /**
     * 递归解决汉诺塔问题
     * @author dxt
     *
     */
    public class TestHanoi {
    	public static void main(String[] args) {
    		Hanoi hanoi = new Hanoi(3);
    		hanoi.solve();
    	}
    }
    
    class Hanoi{
    	//模拟圆盘,圆盘的个数,同时指定圆盘编号,从上到下,从1到totalDisks
    	private int totalDisks;	
    	
    	public Hanoi(int disks) {
    		this.totalDisks = disks;
    	}
    	/**
    	 * 指定初始原始塔柱、辅助塔柱、目标塔柱
    	 */
    	public void solve() {
    		moveTower(totalDisks, 1, 3, 2);
    	}
    	/**
    	 * 递归实现汉诺塔移动
    	 * @param numDisks	圆盘
    	 * @param start		原始塔柱
    	 * @param end		目标塔柱
    	 * @param temp		辅助塔柱
    	 */
    	public void moveTower(int numDisks, int start, int end, int temp) {
    		if(numDisks == 1) {
    			moveOneDisk(numDisks, start, end);
    		}else {
    			moveTower(numDisks-1, start, temp, end);	//关系转换	
    			moveOneDisk(numDisks, start, end);
    			moveTower(numDisks-1, temp, end, start);
    		}
    	}
    	/**
    	 * 输出依次移动的过程
    	 * @param start
    	 * @param end
    	 */
    	public void moveOneDisk(int Disk, int start, int end) {
    		System.out.println(Disk+ ": " +start + "---->" + end);
    	}
    }
    

    结果
    p2
    更简单的代码

    /**
     * 汉诺塔问题
     * @author dxt
     *
     */
    public class Hanoitower {
    	public static void main(String[] args) {
    		moveTower(3, 'a', 'b', 'c');
    	}
    	
    	/**
    	 * 将a上的num个盘移动到c
    	 * @param num 	盘的个数
    	 * @param a		起始盘
    	 * @param b		辅助盘
    	 * @param c		目标盘
    	 */
    	public static void moveTower(int num, char a, char b, char c) {
    		//只有一个盘时
    		if(num == 1) {
    			System.out.println(1 + " move: " + a + " --> " + c);
    		}else {	//有两个或超过两个盘时
    			moveTower(num-1, a, c, b);
    			System.out.println(num + " move: " + a + " --> " + c);
    			moveTower(num-1, b, a, c);
    		}
    	}
    }
    

    总结

    1. 如何理解汉诺塔解决思路?答:在确定第n个圆盘的位置中做了三件事,将最上面n-1个圆盘移到辅助塔座上,将第n个圆盘移动到目标塔座上,将辅助塔座上的n-1个圆盘移到目标塔座上。
    2. 解决n个圆盘的汉诺塔问题需要移动多少次圆盘呢?答:设n个圆盘的moveTower()操作需要进行F(n)次移动,那么由程序可知F(n) = 2 x F(n-1) + 1 (第一个F(n-1)表示将原始塔座上的n-1个圆盘移到辅助塔座上,第二个F(n-1)表示将辅助塔座上的n-1个圆盘移到目标塔座上) 。等式两边同时+1,得F(n)+1 = 2(F(n-1) + 1),初始F(1) = 1,计算等比数列得 F(n) = 2n -1。即解决n个圆盘的汉诺塔问题需要移动2n-1次圆盘。
    展开全文
  • Hanoi塔问题

    2017-05-04 10:28:36
    假设有三个分别命名为x、y、z的圆柱形塔座,在塔座x上插有n个半径大小各不相同,以小到大由上而编号为1,2,····,n,如图所示。现在要求将X轴上的n个圆盘移至Z上并仍按原来的顺序叠放,圆盘移动时必须遵循...

    Hanoi塔问题——递归方法求解    

    Hanoi塔问题
     

    假设有三个分别命名为x、y、z的圆柱形塔座,在塔座x上插有n个半径大小各不相同,以小到大由上而下编号为1,2,····,n,如图所示。现在要求将X轴上的n个圆盘移至塔Z上并仍按原来的顺序叠放,圆盘移动时必须遵循以下规则:

    1.每次只能移动一个圆盘

    2.圆盘可以插在X、Y、Z任意一个塔座上

    3.任何时刻都不能将一个较大的圆盘压在较小圆盘之上

    如何实现圆盘的移动呢?这就要用到我们强大的递归思想。设一个变量n用来调用任意一个圆盘,当n=1时,只要将一号圆盘从X上移动到Z上即可;当n>1,需要利用Y做中间塔,若能设法将压在n号盘上的n-1个圆盘从X移至Y上,然后再将n号盘移到Z上,最后将Y上的n-1个圆盘移到Z上即可!而整个过程中对那n-1个圆盘进行的两次整体操作都可以分别作为一个完整的Hanoi问题。

    由此求解的C函数如下:

    void move(char a,int n,char c)

    {

    //此函数的操作为:将a塔上编号为n的圆盘移至c塔上

    //此处省略若干字。。。

    }

    void Hanoi(int n,char a,char b,char c)

    //将塔座a上的n个圆盘搬到c上,b作为中间塔

    {

    if(n==1)move(x,1,z);

    else

    {

    Hanoi(n-1,x,z,y);

    move(x,n,z);

    Hanoi(n-1,y,x,z);

    }

    }

    可以看出,整个程序都不需要用到实际用于存放Hanoi塔的存储空间(因为算法与客观存在的数据无关嘛),所以move函数可以写成:printf(“将%i号盘从%c塔移到%c塔”,n,a,c);

    展开全文
  • 双色Hanoi塔问题

    2009-10-13 11:24:03
    各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则(1):每次只能移动1个...
  • Hanoi塔问题分析

    千次阅读 多人点赞 2017-12-06 20:10:31
     关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是...

    简介

         关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是比较丰富的。

     

    问题描述

        这个问题起源于一个类似传说故事,在Hanoi这个地方有一个寺庙,这里有3根柱子和64个大小不同的金碟子。每个碟子有一个孔可以穿过。所有的碟子都放在第一个柱子上,而且按照从上到下碟子的大小依次增大的顺序摆设。如下图:

        现在,假定寺庙里的僧侣要移动这些碟子,将它们从最左边移动到最右边的柱子上。不过移动的规则如下:

    1. 每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。

    2. 不能将大碟子放到小碟子的上面。

        按照前面这个规则,我们该怎么去移动这些碟子呢?假定单位时间内可以移动一片碟子,那么最终移动这些碟子到目的柱子需要多长的时间呢?

     

    问题分析 

        在分析这个问题的时候,我们可以先从一些简单的场景来看怎么来移动碟子保证可以达到目的。假定我们有3个碟子,那么移动它们的过程如下图:

        我们假定柱子从左到右分别为a, b, c。从前面移动碟子的步骤可以看到,我们要将a上面的两个碟子先移动到中间的b柱子作为过渡,然后再将最下面的柱子移动到目的c柱子,然后再将上面的两个碟子移过来。在将最下面的碟子移动到c之前,首先的步骤1, 2, 3是将上面的碟子移动到柱子b。而将最下面碟子移动后,上面的两个碟子又要移动一遍,不过是从b移动到c,只是借助的柱子不一样。

        所以,从上面的过程,我们可以看到一个可以递归解决问题的思路,如下图:

     

        如图所示,首先我们针对有n个碟子的柱子a,将n-1个碟子移动到柱子b。假定这个问题为S(n)表示移动的步数,则上面的问题是S(n)的一个子问题S(n-1)。这一步对应步骤1。然后将最下面的碟子移动到柱子c,最后再将n-1个碟子移动到c。后面这一步也相当于S(n)的子问题S(n-1)。对应步骤3.它和前面第一步移动n-1个碟子唯一不同的地方在于第一步是借助c将n-1个碟子从a移动到b,而最后这一步是借助a将n-1个碟子从b移动到c。除了借助的柱子和目的柱子不一样,其他的都是一样的。

        这样我们就可以很容易得到一个这样的推导关系: 

    S(n) = 2S(n - 1) +1

        再考虑一种初始的情况,假定只有一个碟子需要移动,我们直接将碟子从a移动到c,那么需要的步骤是1步。因此可以说S(1) = 1。

     

    进一步推导

        有了前面的归纳关系,我们可以很容易得到如下的一组推导结果:

          S(1) = 1

          S(2) = 2 x S(1) + 1 = 2 + 1 = 3

          S(3) = 2 x S(2) + 1 = 2 x 3 + 1 = 7

          S(4) = 2 x S(3) +1 = 2 x 7 + 1 = 15

        从这些得出来的结果里,似乎还看不到多少有规律的地方。不过我们可以采取一种根据递推原则代换的方式来尝试发现规律。前面的推导关系里有S(n) = 2 x S(n - 1) +1,那么我们将有如下的推导:

         这里,我们发现什么规律没?原来,这里似乎符合如下的一个等式:

         当我们最终一路递推到T1的时候,它将满足如下的形式:

        这似乎是我们所求得的结果了。当然,这种推导也有可能会出错。最好的情况是我们还需要验证一下它。验证的方法可以考虑用数学归纳法。因为过程比较简单,这里就不再赘述了。最终可以验证出来结果是满足以上等式的。从前面的推导我们可以看出,最终要实现将64个碟子移动到目的柱子,需要的时间是2的64次方这个量级的。在一定程度上,用计算机的内置数据类型都没法表示这个数值。

     

    代码实现

        前面的分析可以发现,从计算机实现来说,这个问题是指数函数级别的,意味着它的增长速度非常快,在一定程度上计算机都无法解决。在一个比较小的数值范围内,我们还是可以做一个参考实现的。有了前面的讨论,我们的完整代码实现如下:

    复制代码
     1 public class Hanoi {  
     2       
     3     public static void move(char a, char b, char c, int n) {  
     4         if(n == 0)  
     5             return;  
     6         move(a, c, b, n-1);  
     7         System.out.printf("Move disk %d from %s to %s\n", n, a, c);  
     8         move(b, c, a, n-1);  
     9     }  
    10   
    11     public static void main(String[] args) {  
    12         move('a', 'b', 'c', 3);  
    13     }  
    14 }  
    复制代码


        这部分代码里,我们递归的退出条件是当最终碟子移走,即n == 0。运行这一段程序的结果如下:

    Java代码   收藏代码
    1. Move disk 1 from a to c  
    2. Move disk 2 from a to b  
    3. Move disk 1 from c to a  
    4. Move disk 3 from a to c  
    5. Move disk 1 from b to c  
    6. Move disk 2 from b to a  
    7. Move disk 1 from c to b  

        和前面图示的过程是完全一致的。当然,在提供的数值比较大的时候,我们这种递归的方式就溢出了。

     

    总结

        Hanoi塔问题是一个经典的递归问题,它本身的数学复杂度达到了指数函数级别。所以使得运算时间的增长非常快。通过一种递归的思路,首先我们可以总结出一个问题的递归描述方式。然后我们再通过不断的代入和分析,去发现形成等式的规律。这是一种发现递归问题等式描述的方法。为了保证方法最终的正确性,我们还需要经常使用数学归纳法来证明这个等式的正确性。

        这部分代码里,我们递归的退出条件是当最终碟子移走,即n == 0。运行这一段程序的结果如下:

    Java代码   收藏代码
    1. Move disk 1 from a to c  
    2. Move disk 2 from a to b  
    3. Move disk 1 from c to a  
    4. Move disk 3 from a to c  
    5. Move disk 1 from b to c  
    6. Move disk 2 from b to a  
    7. Move disk 1 from c to b  

        和前面图示的过程是完全一致的。当然,在提供的数值比较大的时候,我们这种递归的方式就溢出了。

     

    总结

        Hanoi塔问题是一个经典的递归问题,它本身的数学复杂度达到了指数函数级别。所以使得运算时间的增长非常快。通过一种递归的思路,首先我们可以总结出一个问题的递归描述方式。然后我们再通过不断的代入和分析,去发现形成等式的规律。这是一种发现递归问题等式描述的方法。为了保证方法最终的正确性,我们还需要经常使用数学归纳法来证明这个等式的正确性。

    展开全文
  • 又是Hanoi塔问题

    2011-03-21 10:41:12
    各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则(1):每次只能移动1...
  • 递归---Hanoi塔问题

    2017-12-19 16:58:45
     关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是...

    http://shmilyaw-hotmail-com.iteye.com/blog/2077098

    简介

         关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是比较丰富的。

     

    问题描述

        这个问题起源于一个类似传说故事,在Hanoi这个地方有一个寺庙,这里有3根柱子和64个大小不同的金碟子。每个碟子有一个孔可以穿过。所有的碟子都放在第一个柱子上,而且按照从上到下碟子的大小依次增大的顺序摆设。如下图:

        现在,假定寺庙里的僧侣要移动这些碟子,将它们从最左边移动到最右边的柱子上。不过移动的规则如下:

    1. 每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。

    2. 不能将大碟子放到小碟子的上面。

        按照前面这个规则,我们该怎么去移动这些碟子呢?假定单位时间内可以移动一片碟子,那么最终移动这些碟子到目的柱子需要多长的时间呢?

     

    问题分析 

        在分析这个问题的时候,我们可以先从一些简单的场景来看怎么来移动碟子保证可以达到目的。假定我们有3个碟子,那么移动它们的过程如下图:

        我们假定柱子从左到右分别为a, b, c。从前面移动碟子的步骤可以看到,我们要将a上面的两个碟子先移动到中间的b柱子作为过渡,然后再将最下面的柱子移动到目的c柱子,然后再将上面的两个碟子移过来。在将最下面的碟子移动到c之前,首先的步骤1, 2, 3是将上面的碟子移动到柱子b。而将最下面碟子移动后,上面的两个碟子又要移动一遍,不过是从b移动到c,只是借助的柱子不一样。

        所以,从上面的过程,我们可以看到一个可以递归解决问题的思路,如下图:

     

        如图所示,首先我们针对有n个碟子的柱子a,将n-1个碟子移动到柱子b。假定这个问题为S(n)表示移动的步数,则上面的问题是S(n)的一个子问题S(n-1)。这一步对应步骤1。然后将最下面的碟子移动到柱子c,最后再将n-1个碟子移动到c。后面这一步也相当于S(n)的子问题S(n-1)。对应步骤3.它和前面第一步移动n-1个碟子唯一不同的地方在于第一步是借助c将n-1个碟子从a移动到b,而最后这一步是借助a将n-1个碟子从b移动到c。除了借助的柱子和目的柱子不一样,其他的都是一样的。

        这样我们就可以很容易得到一个这样的推导关系: 

    S(n) = 2S(n - 1) +1

        再考虑一种初始的情况,假定只有一个碟子需要移动,我们直接将碟子从a移动到c,那么需要的步骤是1步。因此可以说S(1) = 1。

     

    进一步推导

        有了前面的归纳关系,我们可以很容易得到如下的一组推导结果:

          S(1) = 1

          S(2) = 2 x S(1) + 1 = 2 + 1 = 3

          S(3) = 2 x S(2) + 1 = 2 x 3 + 1 = 7

          S(4) = 2 x S(3) +1 = 2 x 7 + 1 = 15

        从这些得出来的结果里,似乎还看不到多少有规律的地方。不过我们可以采取一种根据递推原则代换的方式来尝试发现规律。前面的推导关系里有S(n) = 2 x S(n - 1) +1,那么我们将有如下的推导:

         这里,我们发现什么规律没?原来,这里似乎符合如下的一个等式:

         当我们最终一路递推到T1的时候,它将满足如下的形式:

        这似乎是我们所求得的结果了。当然,这种推导也有可能会出错。最好的情况是我们还需要验证一下它。验证的方法可以考虑用数学归纳法。因为过程比较简单,这里就不再赘述了。最终可以验证出来结果是满足以上等式的。从前面的推导我们可以看出,最终要实现将64个碟子移动到目的柱子,需要的时间是2的64次方这个量级的。在一定程度上,用计算机的内置数据类型都没法表示这个数值。

    #include <iostream>
    
    using namespace std;
    
    //Hanoi塔问题,借助c,将n个盘子从a移到b
    void hanoi(int n,char a,char b,char c)
    {
        if(n>0)
        {
            hanoi(n-1,a,c,b);//借助b,将n-1个盘子从a移到c上
            cout<<"将"<<a<<"中最大的盘子从"<<a<<"移到"<<b<<endl;
            hanoi(n-1,c,b,a);//借助a,将n-1个盘子从c移到b上
        }
    }
    int main()
    {
        char a='A',b='B',c='C';
        hanoi(3,a,b,c);
        return 0;
    }
    #include <iostream>
    #include <stdio.h>
    using namespace std;
    
    //第一个塔为初始塔,中间的塔为借用塔,最后一个塔为目标塔
    int i=1;//记录步数
    void move(int n,char from,char to) //将编号为n的盘子由from移动到to
    {
        printf("第%d步:将%d号盘子%c---->%c\n",i++,n,from,to);
    }
    void hanoi(int n,char from,char denpend_on,char to)
    //将n个盘子由初始塔移动到目标塔(利用借用塔)
    {
        if (n==1)
        move(1,from,to);//只有一个盘子是直接将初塔上的盘子移动到目的地
        else
        {
          hanoi(n-1,from,to,denpend_on);//先将初始塔的前n-1个盘子借助目的塔移动到借用塔上
          move(n,from,to);              //将剩下的一个盘子移动到目的塔上
          hanoi(n-1,denpend_on,from,to);//最后将借用塔上的n-1个盘子移动到目的塔上
        }
    }
    int main()
    {
         printf("请输入盘子的个数:\n");
         int n;
         scanf("%d",&n);
         char x='A',y='B',z='C';
         printf("盘子移动情况如下:\n");
         hanoi(n,x,y,z);//A--->C
         return 0;
    }


    移动步骤:

    假设a,b,c排成一个三角形,a--->b--->c--->a构成顺时针循环,移动圆盘过程中,若奇数次移动,则将最小的圆盘移动到顺时针方向的下一塔,若是偶数次移动,则保持最小的圆盘不动,在其他两个塔之间将较小的圆盘移动到另一个上。

    展开全文
  • 如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘 时应遵守以下移动规则: 规则(1):每次只能移动1个圆盘; 规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上; ...
  • 问题 I: 双色Hanoi塔问题

    千次阅读 2018-08-06 15:16:08
    各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:  规则(1):每次只能移动...
  • 13.11 双色Hanoi塔问题

    2021-06-20 21:40:57
    各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。 现要求将塔座 A 上的这一叠圆盘移到塔座 B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则(1):每次只能移动...
  • 今天为大家讲一道非常有趣的问题hanoi塔问题,...各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆...
  • 各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则: 规则(1):每次只能移动1 ...
  • 关于Hanoi塔问题的分析,在网上的文章都写烂了。之所以打算写这篇文章,更多的是针对这个问题相关的各种数学思路和代码实现过程做一个总结。它虽然是一个看似简单的问题,后面引申出来的问题推导方法和思路还是比较...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 991
精华内容 396
关键字:

hanoi塔问题如下图所示