首页 > 代码库 > 汉诺塔问题(递归、栈)

汉诺塔问题(递归、栈)

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

方法一:递归实现

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

 

汉诺塔问题(递归、栈)