zoukankan      html  css  js  c++  java
  • 栈和队列----用栈求解汉诺塔问题

    用栈求解汉诺塔问题

      

      汉诺塔问题比较经典,现在修改一下汉诺塔游戏的规则:规定不能直接从左移动到右,也不能直接从右移动到左,必须经过中柱,求解当塔有N层的时候,打印最优移动过程和最优移动总步数。

      可以采用两个方法解决。方法一采用递归的方法;方法二采用非递归的方法,用栈来模拟汉诺塔的三个塔。

    package com.test;
    
    import java.util.Stack;
    
    /**
     * Created by Demrystv.
     */
    public class SolveHanoiWithStack {
    
        //递归的方法,左->中,右->中,中->左,中->右,都是需要三个步骤,左->右,右->左,都是需要五个步骤
        public int hanoiProblem1(int num, String left, String mid, String right){
            if (num < 1){
                return 0;
            }
            return process(num, left, mid, right, left, right);
        }
    
        private int process(int num, String left, String mid, String right, String from, String to){
            if (num==1){
                if (from.equals(mid) || to.equals(mid)){
                    System.out.println("Move 1 from " + from + " to " + to);
                    return 1;
                }else {
                    System.out.println("Move 1 from " + from + " to " + mid);
                    System.out.println("Move 1 from " + mid + " to " + to);
                    return 2;
                }
            }
    
            if (from.equals(mid) || to.equals(mid)){
                String another = (from.equals(left)) || (to.equals(left)) ? right : left;
                int part1 = process(num-1, left, mid, right, from, another);
                int part2 = 1;
                System.out.println("Move " + num + " from " + from + " to " + another);
                int part3 = process(num-1, left, mid, right, another, to);
                return part1 + part2 + part3;
            }else {
                int part1 = process(num-1, left, mid, right, from, to);
                int part2 = 1;
                System.out.println("Move " + num + " from " + from + " to " + mid);
                int part3 = process(num-1, left, mid, right, to, from);
                int part4 = 1;
                System.out.println("Move " + num + " from " + mid + " to " + to);
                int part5 = process(num-1, left, mid, right, from, to);
                return part1 + part2 + part3 + part4 + part5;
            }
        }
    
    
    
        //非递归方法用到的枚举类,因为不能直接从左到右,所以就只有四个动作
        public enum Action{
            No, LToM, MToL, MToR, RToM
        }
    
        //非递归的方法,用栈来模拟整个过程
        //核心思想:
        // 需要遵守两个原则,
        // 一个是不能违反小压大的原则,from栈弹出的元素num想压入到to栈中,那么num的值必须小于等于当前to栈的栈顶
        // 另一个是相邻不可逆原则,即不能上一步是左到中,下一步是中到左,不满足最小步数
        // 由这两个原则可以推出非递归方法的两个结论:
        // 1.游戏的第一个动作一定是 左 到 中
        // 2.四个动作中只有一个动作和相邻不可逆原则,其余三个一定都会违反,可以证明
        // 因此,每一步只有一个动作达标,那么只要每一步都根据这两个原则考察所有的动作即可,哪个满足就进行哪个动作,按照顺序走下来即可。
        public int hanoiProblem2(int num, String left, String mid, String right){
            Stack<Integer> lS = new Stack<Integer>();
            Stack<Integer> mS = new Stack<Integer>();
            Stack<Integer> rS = new Stack<Integer>();
            lS.push(Integer.MAX_VALUE);
            mS.push(Integer.MAX_VALUE);
            rS.push(Integer.MAX_VALUE);
            for (int i=num; i>0; i--){
                lS.push(i);
            }
    
            Action[] record = {Action.No};
            int step = 0;
    
            while (rS.size() != num + 1){
                step += fStackToStack(record, Action.MToL, Action.LToM, lS, mS, left, mid);
                step += fStackToStack(record, Action.LToM, Action.MToL, mS, lS, mid, left);
                step += fStackToStack(record, Action.RToM, Action.MToR, mS, rS, mid, right);
                step += fStackToStack(record, Action.MToR, Action.RToM, rS, mS, right, mid);
            }
            return step;
        }
        private int fStackToStack(Action[] record, Action preNoAct, Action nowAct, Stack<Integer> fStack, Stack<Integer> tStack,
                                  String from, String to){
            if(record[0] != preNoAct && fStack.peek() < tStack.peek()){
                tStack.push(fStack.pop());
                System.out.println("Move " + tStack.peek() + " from " + from + " to " + to);
                record[0] = nowAct;
                return 1;
            }
            return 0;
        }
    }
  • 相关阅读:
    SQL SET NOCOUNT (Transact-SQL)
    Delphi WinAPI DragAcceptFiles、DragQueryFile、DragFinish、DragQueryPoint
    Delphi Thread线程错误:Canvas doesn't allow drawing
    Delphi ADOQuery错误:ADOQuery1:commandtext does not return a result set
    医学-药物-未分类-胃舒平(复方氢氧化铝)
    SQL 查询时间超时已过期(SQL 2000、SQL2005、SQL2008、SQL2012等)
    SQL 数据库引擎语句 sp_executesql 的使用介绍(Transact-SQL)
    android 定位代码
    Centos7开放及查看端口
    非常详细的sklearn介绍
  • 原文地址:https://www.cnblogs.com/Demrystv/p/9292776.html
Copyright © 2011-2022 走看看