用栈来求解汉诺塔变形问题

package stackAndQueue;

import java.util.Stack;

/**
 * 用栈来求解汉诺塔问题:HanoiStack【3】
 *
 * 【问题描述】:将汉诺塔游戏(小压大)规则修改,不能从左(右)侧的塔直接移到右(左)侧,而是必须经过中间塔。
 *
 * 求当塔有N层时,打印最优移动过程和最优移动步数。如N=2,记上层塔为1,下层为2.则打印:1:left->mid;1
 *
 * 由于必须经过中间,实际动作只有4个:左L->中M,中->左,中->右R,右->中。
 *
 * 原则:①小压大;②相邻不可逆(上一步是L->M,下一步绝不能是M->L)
 *
 * 非递归方法核心结论:1.第一步一定是L-M;2.为了走出最少步数,四个动作只可能有一个不违反上述两项原则。
 *
 * 核心结论2证明:假设前一步是L->M(其他3种情况略)
 *
 * a.根据原则①,L->M不可能发生;b.根据原则②,M->L不可能;c.根据原则①,M->R或R->M仅一个达标。
 *
 * So,每走一步只需考察四个步骤中哪个步骤达标,依次执行即可。
 *
 * @author xiaofan
 */
public class HanoiStack {
    private enum Action {
        None, LToM, MToL, MToR, RToM
    };

    static Action preAct = Action.None; // 上一步操作,最初什么移动操作都没有

    final static int num = 4; // 汉诺塔层数

    public static void main(String[] args) {
        int steps = transfer(num);
        System.out.println("It will move " + steps + " steps.");
    }

    private static int transfer(int n) {
        Stack<Integer> lS = new Stack<>(); // java7菱形用法,允许构造器后面省略范型。
        Stack<Integer> mS = new Stack<>();
        Stack<Integer> rS = new Stack<>();
        lS.push(Integer.MAX_VALUE);// 栈底有个最大值,方便后续可以直接peek比较
        mS.push(Integer.MAX_VALUE);
        rS.push(Integer.MAX_VALUE);
        for (int i = n; i > 0; i--) {
            lS.push(i);// 初始化待移动栈
        }
        int step = 0;

        while (rS.size() < n + 1) {// n+1,因为rS.push(Integer.MAX_VALUE);等于n+1说明全部移动完成
            step += move(Action.MToL, Action.LToM, lS, mS);// 第一步一定是LToM
            step += move(Action.LToM, Action.MToL, mS, lS);// 只可能有这4种操作
            step += move(Action.MToR, Action.RToM, rS, mS);
            step += move(Action.RToM, Action.MToR, mS, rS);
        }
        return step;
    }

    /**
     * 实施移动操作.
     *
     * @param cantAct
     *            不能这样移动
     * @param nowAct
     *            即将执行的操作
     * @param fromStack
     *            起始栈
     * @param toStack
     *            目标栈
     * @return step(成功与否)
     */
    private static int move(Action cantAct, Action nowAct, Stack<Integer> fromStack, Stack<Integer> toStack) {
        if (preAct != cantAct && toStack.peek() > fromStack.peek()) {
            toStack.push(fromStack.pop()); // 执行移动操作
            System.out.println(toStack.peek() + ":" + nowAct);
            preAct = nowAct; // 更新“上一步动作”
            return 1;
        }
        return 0;
    }
}

代码地址:https://github.com/zxiaofan/Algorithm/tree/master/src/stackAndQueue

时间: 2024-09-20 18:34:28

用栈来求解汉诺塔变形问题的相关文章

java求解汉诺塔问题示例_java

思路如下: 要实现3阶汉诺塔的求解步骤,也就是说初始状态时,A上从上到下有三个盘子,分别为1号盘.2号盘和3号盘,其中1号盘最小,3号盘最大:判断剩余盘子个数,如果只有一个盘子就退出迭代,如果有大于一个盘子就继续迭代.代码如下: 复制代码 代码如下: public class HanoiTower {    public static void moveDish(int level, char from, char inter, char to) {        if (level == 1)

【Python学习】Python解决汉诺塔问题

参考文章:http://www.cnblogs.com/dmego/p/5965835.html 一句话:学程序不是目的,理解就好:写代码也不是必然,省事最好:拿也好,查也好,解决问题就好! 信息时代不用信息就是罪过,直接抄不加理解与应用,就不是自己的,下次遇到还是不会,或许其中的某一个细节就能够用于各个问题的解决,共勉 学习一个东西总会遇到一些经典的问题,学习Python第二天尝试看一下汉诺塔问题,还是百度,看看解题思路,纯粹是重温初中课堂,越活越回去了  汉诺塔的图解递归算法 一.起源: 汉

递归解决汉诺塔问题

前言:汉诺塔问题是源于印度一个古老传说.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在第三根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘. 我们用递归算法来解决这个问题,在解决之前首先介绍一下什么是递归算法. 1.递归算法 在解决一些复杂问题时,为了降低问题的复杂程序,通常是将问题逐层分解,最后归结为一些最简单的问题.这种将问题逐层分解的过程,并没有对问题进行求解,而

汉诺塔算法c++出现错误

问题描述 汉诺塔算法c++出现错误 #include using namespace std; //圆盘的个数最多为64 const int MAX = 64; //用来表示每根柱子的信息 struct st{ int s[MAX]; //柱子上的圆盘存储情况 int top; //栈顶,用来最上面的圆盘 char name; //柱子的名字,可以是A,B,C中的一个 int Top() //取栈顶元素 { return s[top]; } int Pop() //出栈 { return s[t

c#汉诺塔的递归算法与解析_C#教程

从左到右 A  B  C 柱 大盘子在下, 小盘子在上, 借助B柱将所有盘子从A柱移动到C柱, 期间只有一个原则: 大盘子只能在小盘子的下面. 如果有3个盘子, 大中小号, 越小的越在上面, 从上面给盘子按顺序编号 1(小),2(中),3(大), 后面的原理解析引用这里的编号. 小时候玩过这个游戏, 基本上玩到第7个,第8个就很没有耐心玩了,并且操作的动作都几乎相同觉得无聊.  后来学习编程, 认识到递归, 用递归解决汉诺塔的算法也是我除了简单的排序算法后学习到的第一种算法. 至于递归,简单来说

学习笔记(菜鸟日志)-&amp;quot;汉诺塔&amp;quot;的递归过程

记得大一上C语言课程的时候我还刚刚会用迅雷下载电影,听不懂,也没认真听过,匆匆几个星期上完了考试.关于"汉诺塔"这样的字眼,也是仅仅记得是在那个书里面出现过而已.最近偶然拿起C语言的书,再次看到了"汉诺塔"递归算法的例子,转好几圈,终于搞明白了.现在花点时间重新这里下思路,一则方便自己以后回忆,二则希望能给和我一样菜的新手们提供参考,三则希望有高人出现对文中不足的地方加以斧正!    关于"汉诺塔"这个古老的益智游戏如果不清楚的,到百度百科一下!

C语言实现汉诺塔游戏_C 语言

操作就是:A B 号码A的塔顶一层放在号码B的塔顶.如1(空格) 3 回车. 话说有人能把我这C的代码添加到QT界面框架上去么?  代码写的不好 ,维护性不够,只能玩8层的,写完以后发现很难拓展,软件工程,设计模式有待提高.... 里面提示输入等级的装B用了,没有实现,大家随便输入个个位数就可以玩了. stackfunc.c #include"STACK.h" #include<stdio.h> extern ceng CENG[SIZE]; //数据入栈 void pus

Java数据结构及算法实例:汉诺塔问题 Hanoi_java

/** * 汉诺塔大学的时候就学过,但是根本没搞明白,唯一知道的就是要用递归的方法来求解. * 问题描述: * 有三根杆子A,B,C.A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小. * 要求按下列规则将所有圆盘移至C杆: * 1.每次只能移动一个圆盘: * 2.大盘不能叠在小盘上面. * 提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆, * 但都必须尊循上述两条规则. * 问:如何移?最少要移动多少次? * 解决方法: * 假设只有2个盘子,柱子分别是A, B, C柱

java 汉诺塔Hanoi递归、非递归(仿系统递归)和非递归规律 实现代码_java

程序如下: 复制代码 代码如下: View Code  /*  * Hanoi塔游戏 问题描述:  * 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.  * 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照  * 大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小  * 顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在  * 三根柱子之间一次只能移动一个圆盘.  *   * fuction:实现 hanoi塔  *