汉诺塔问题(递归、栈)

修改一下汉诺塔的游戏规则,现在不能直接从左边走到右边,也不能直接右边走到左边。

方法一:递归实现

现在分析一下,比如左边有1~n,那么移动最后一个的情况,就是:

1.1-n-1从左边移动到右边

2.n从左边移动到中间

3.1-n-1从右边移动到左边

4.n从中间移动到右边

5.1-n-1从左边移动到右边

那么,假如我有这样一个f(range,from,to)那么我需要求解的就是f(n,lrft,right),原子情况就是从只有一个数的时候,直接左边中间右边即可。

 1  public static int process(int num, String from, String to) {
 2         if (num == 1) {
 3             System.out.println("move 1 from " + from +" to middle");
 4             System.out.println("move 1 from middle to " + to);
 5             return 2;
 6         }
 7         else {
 8             int p1 = process(num - 1, from, to);
 9             System.out.println("move "+ num + " from " + from +" to middle");
10             int p2 = process(num - 1, to, from);
11             System.out.println("move "+ num + " from middle to " + to);
12             int p3 = process(num - 1, from, to);
13             return  p1 + p2 + p3 +2;
14         }
15     }

方法二:使用栈来实现

这样思考,一共有的动作一共就四种:L2M M2L M2R R2M

在任何一个时刻,要想最少移动次数,并且满足小压大原则,则只有一种情况能够得到满足。

证明如下:

假如上一个动作是L2M,那么不可能L2M(小压大),也不可能M2L(最优),那么剩下M2R和R2M,就一定有一种情况会得到满足。其他情况同理。

所以使用三个栈分别记录左中右的数,然后每次检测出满足条件的那个来继续即可。由于每个都会去除每个栈的栈顶元素来进行比较,所以为了避免判断是否为空,就首先在每个栈的栈顶压入最大值以最为保障。结束的条件就是最右边的栈中元素个数为总的元素个数。

 1  public static enum Action {
 2         No,L2M, M2L,M2R,R2M
 3     }
 4     public static int hanoiProblem2(int num) {
 5         Stack<Integer> ls = new Stack<Integer>();
 6         Stack<Integer> ms = new Stack<Integer>();
 7         Stack<Integer> rs = new Stack<Integer>();
 8         ls.push(Integer.MAX_VALUE);
 9         ms.push(Integer.MAX_VALUE);
10         rs.push(Integer.MAX_VALUE);
11         for (int i = num; i > 0; i--) {
12             ls.push(i);
13         }
14         Action[] preAction = {Action.No};
15         int step = 0;
16         while (rs.size() != num + 1) {
17             step += fStack2Stack(preAction,Action.M2L,Action.L2M,ls,ms);
18             step += fStack2Stack(preAction,Action.L2M,Action.M2L,ms,ls);
19             step += fStack2Stack(preAction,Action.R2M,Action.M2R,ms,rs);
20             step += fStack2Stack(preAction,Action.M2R,Action.R2M,rs,ms);
21         }
22         return step;
23     }
24     public static int fStack2Stack(Action[] preAction, Action noAction, Action curAction,
25                                    Stack<Integer> fStack, Stack<Integer> tStack) {
26         if (preAction[0] == noAction || fStack.peek() >= tStack.peek()) {
27             return 0;
28         }
29         preAction[0] = curAction;
30         tStack.push(fStack.pop());
31         return 1;
32     }

时间: 2024-08-24 13:18:12

汉诺塔问题(递归、栈)的相关文章

汉诺塔问题递归算法分析

汉诺塔问题递归算法分析: 一个庙里有三个柱子,第一个有64个盘子,从上往下盘子越来越大.要求庙里的老和尚把这64个盘子全部移动到第三个柱子上.移动的时候始终只能小盘子压着大盘子.而且每次只能移动一个. 1.此时老和尚(后面我们叫他第一个和尚)觉得很难,所以他想:要是有一个人能把前63个盘子先移动到第二个柱子上,我再把最后一个盘子直接移动到第三个柱子,再让那个人把刚才的前63个盘子从第二个柱子上移动到第三个柱子上,我的任务就完成了,简单.所以他找了比他年轻的和尚(后面我们叫他第二个和尚),命令:

从&quot;汉诺塔&quot;经典递归到JS递归函数

前言 参考<JavaScript语言精粹> 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决.递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题. "汉诺塔"经典递归问题 "汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏: 题目如下: 塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱子上的所有圆盘都按从大到小的顺序排列.目标是通过

【C/C++学院】0817-递归汉诺塔 双层递归 /CPP结构体 /面向过程与面向对象的编程模式/类的常识共用体实现一个类的特征/QT应用于类以及类的常识

递归汉诺塔 双层递归 #include <iostream> void han(int n, char A, char B, char C) { static int num = 1; std::cout << "第" << num << "次"; num++; if (n<1) { return; } else { han(n - 1, A, C, B); std::cout << A <&l

用C语言实现汉诺塔自动递归演示程序

用C语言实现汉诺塔自动递归演示程序 程序实现效果 1.变界面大小依照输入递归数改变. 2.汉诺塔自动移动演示. 3.采用gotoxy实现流畅刷新. 4.保留文字显示递归流程 程序展示及实现 github地址:https://github.com/404name/C-game 0.主体思路 输入要递归的汉诺塔数目,在原来的汉诺塔基础上新增move_play函数展示递归,用next数组存储每种移动状态.对应的从哪到哪可自动对应相应的移动方式自动移动. 1.变界面大小依照输入递归数改变 init函数按

Hanoi(汉诺塔问题)用栈来求解

学习c语言必定会遇到递归问题,学递归一定知道汉诺塔问题:如何将圆盘移动到另一根柱子上,但是圆盘的顺序不能改变. 有XYZ三个轴,n个盘子放在X轴上,目标是将N个盘子从X轴上移动到Z轴上 这里我们假设有这样一个方法F,F:将N个盘子按照原来的顺序从X轴上移动到Z轴上 如果只有一个盘子的话,一步到位 但是有N个(N>1)是,为了实现目标,我们需要利用中间轴来倒腾,我们将最后一个盘子上方的N-1个盘子按照顺序不变的方式(方法F)(这并不是移动步数最少的办法)先移动到Y轴,在将最后一个剩余的盘子移动到Z

HDU 2064 汉诺塔III(递归)

题目链接 Problem Description 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到大顺序串着由64个圆盘构成的塔.目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面.现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面.Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在

Hanio汉诺塔代码递归实现

1.背景介绍 Hanio (汉诺塔,又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘. 我们姑且不去追溯传说的缘由,现考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序.这需要多少次移动呢?这里需要递归的方法.假设有n片,移动次数是f(n).显然f

[算法]——汉诺塔的递归深度

今天早晨在上班的路上,一好朋友突然提到之前的一个计算机的考题,汉诺塔(相信大家都玩过)的递归深度. 由于很久没有看算法,以及脑容量有限,当时没有多想. 来到公司后,把公式列了一下,终于清晰多了. 下面假设3根柱子编号为1,2,3. 主要思路: 把n个圆盘从3号移到1号 = 把n-1个圆盘从3号移到2号 + 把第n个圆盘从3号移到1号 + n-1个圆盘从2号移到1号 列出公式: f(n) = f(n-1) + 1 + f(n-1) = 2f(n-1) + 1 计算公式: 接下来就是数学题了, 利用

【Python实践-3】汉诺塔问题递归求解

1 # -*- coding: utf-8 -*- 2 #汉诺塔移动问题 3 # 定义move(n,a,b,c)函数,接受参数n,表示3个柱子A.B.C中第1个柱子A的盘子数量 4 # 然后打印出把所有盘子从A借助B移动到C的方法 5 def move(n,a,b,c): 6 if n==1: 7 print('move', a, '-->', c) 8 else: 9 move(n-1,a,c,b) 10 move(1,a,b,c) 11 move(n-1,b,a,c) 12 move(5,'

汉诺塔问题--递归实现

/*汉诺塔问题*/ #include <stdio.h> #include <stdlib.h> //定义n为移动的层数,x,y,z分别代表三根柱子,表示把前n层塔牌从x借助y移动到z void move(int n,char x,char y,char z) { if(n == 1) { printf("从 %c 移动到 %c \n",x,z); } else { move(n-1,x,z,y); printf("从 %c 移动到 %c \n&quo