一、题目
汉诺塔问题比较经典,这里修改一下游戏规则:现在限制不能从最左侧的塔直接移动到最右侧,也不能从最右侧直接移动到最左侧,而是必须进过中间。求当塔有N层时候,打印最优移动过程和最优移总步数。
例如,当塔数为两层时,最上层的塔记为1,最下层的塔记为2,如下图1所示:
图1. 两层汉诺塔图
则打印:
move 1 from left to mid
move 1 from mid to right
move 2 from left to mid
move 1 from right to mid
move 1 from mid to left
move 2 from mid to right
move 1 from left to mid
move 1 from mid to right
It will move 8 steps.
二、要求
用一下两种方法解决。
(1)方法一:递归的方法;
(2)方法二:非递归的方法,用栈来模拟汉诺塔的三个塔。
三、解答
(1)方法一:递归的方法。(本篇博客主要介绍非递归方法,递归的方法就不贴代码了,网上有很多)
(2)方法二:非递归的方法,用栈来解决。
四、可运行代码:
import java.util.Stack; public class StackOfhanoiProblem { public static void main(String[] args) { StackOfhanoiProblem s = new StackOfhanoiProblem(); int a = s.hanoiProblem(2, "left", "mid", "right"); System.out.println("It will move "+a+" steps."); } public enum Action{ No,LToM,MToL,MToR,RToM //描述四个动作:左到中,中到左,中到右,右到中 } public static int hanoiProblem(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) { //右侧栈如果存放的数量没有达到num+1时,说明没有全部移动过去,则执行循环 step += fStackTotStack(record, Action.MToL, Action.LToM, ls, ms, left, right); step += fStackTotStack(record, Action.LToM, Action.MToL, ms, ls, mid, left); step += fStackTotStack(record, Action.RToM, Action.MToR, ms, rs, mid, right); step += fStackTotStack(record, Action.MToR, Action.RToM, rs, ms, right, mid); } return step; } public static int fStackTotStack(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; } }
五、运行结果截图: