• 汉诺塔问题(递归、栈)


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

    方法一:递归实现

    现在分析一下,比如左边有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     }
    View Code

    方法二:使用栈来实现

    这样思考,一共有的动作一共就四种: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     }
    View Code
  • 相关阅读:
    css学习记录(css元素类型)
    一个面向对象的js问题 大家帮忙看看
    css选择器记录
    css学习记录
    如何进行高效JavaScript单元测试
    js拖动库介绍
    PHP 方法记录
    jquery学习笔记(一)
    windows8 后台传递下载
    .NET Framework 4.5 RC 更新
  • 原文地址:https://www.cnblogs.com/futurehau/p/5878890.html
Copyright © 2020-2023  润新知